first commit

This commit is contained in:
云泽网
2025-07-27 21:42:34 +08:00
commit c1cce5ccb4
2779 changed files with 340042 additions and 0 deletions
@@ -0,0 +1,81 @@
<?php
// +----------------------------------------------------------------------
// | likeshop开源商城系统
// +----------------------------------------------------------------------
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
// | gitee下载:https://gitee.com/likeshop_gitee
// | github下载:https://github.com/likeshop-github
// | 访问官网:https://www.likeshop.cn
// | 访问社区:https://home.likeshop.cn
// | 访问手册:http://doc.likeshop.cn
// | 微信公众号:likeshop技术社区
// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
// | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
// | 禁止对系统程序代码以任何目的,任何形式的再发布
// | likeshop团队版权所有并拥有最终解释权
// +----------------------------------------------------------------------
// | author: likeshop.cn.team
// +----------------------------------------------------------------------
namespace app\common\logic;
use app\common\model\User;
use app\common\model\AccountLog;
class AccountLogLogic{
/**
* Notes:记录会员账户流水,如果变动类型是成长值,且是增加的,则调用更新会员等级方法。该方法应在添加用户账户后调用
* @author: cjh 2020/12/15 11:49
* @param int $user_id 用户id
* @param float $amount 变动数量
* @param int $change_type 变动类型:1-增加;2-减少
* @param int $source_type 来源类型
* @param string $remark 说明
* @param string $source_id 来源id
* @param string $source_sn 来源单号
* @param string $extra 额外字段说明
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function AccountRecord($user_id,$amount,$change_type,$source_type,$remark ='',$source_id ='',$source_sn='',$extra=''){
$user = User::get($user_id);
if(empty($user)){
return false;
}
$type = AccountLog::getChangeType($source_type);
$left_amount = '';
switch ($type){
case 'money':
$left_amount = $user->user_money;
break;
case 'integral':
$left_amount = $user->user_integral;
break;
case 'growth':
$left_amount = $user->user_growth;
break;
case 'earnings':
$left_amount = $user->earnings;
}
$account_log = new AccountLog();
$account_log->log_sn = createSn('account_log','log_sn','',4);
$account_log->user_id = $user_id;
$account_log->source_type = $source_type;
$account_log->source_id = $source_id;
$account_log->source_sn = $source_sn;
$account_log->change_amount = $amount;
$account_log->left_amount = $left_amount;
$account_log->remark = AccountLog::getRemarkDesc($source_type,$source_sn,$remark);
$account_log->extra = $extra;
$account_log->change_type = $change_type;
$account_log->create_time = time();
$account_log->save();
//更新会员等级
if($type === 'growth' && $change_type == 1){
UserLevelLogic::updateUserLevel($user_id);
}
return true;
}
}
@@ -0,0 +1,51 @@
<?php
// +----------------------------------------------------------------------
// | likeshop开源商城系统
// +----------------------------------------------------------------------
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
// | gitee下载:https://gitee.com/likeshop_gitee
// | github下载:https://github.com/likeshop-github
// | 访问官网:https://www.likeshop.cn
// | 访问社区:https://home.likeshop.cn
// | 访问手册:http://doc.likeshop.cn
// | 微信公众号:likeshop技术社区
// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
// | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
// | 禁止对系统程序代码以任何目的,任何形式的再发布
// | likeshop团队版权所有并拥有最终解释权
// +----------------------------------------------------------------------
// | author: likeshop.cn.team
// +----------------------------------------------------------------------
namespace app\common\logic;
use app\common\model\AfterSaleLog;
/**
* 售后记录日志
* Class AfterSaleLogLogic
* @package app\common\logic
*/
class AfterSaleLogLogic
{
public static function record($type, $channel, $order_id, $after_sale_id, $handle_id, $content, $desc = '')
{
if (empty($content)) {
return true;
}
$log = new AfterSaleLog();
$log->type = $type;
$log->channel = $channel;
$log->order_id = $order_id;
$log->after_sale_id = $after_sale_id;
$log->handle_id = $handle_id;
$log->content = AfterSaleLog::getLogDesc($content);
$log->create_time = time();
if ($desc != ''){
$log->content = AfterSaleLog::getLogDesc($content).'('.$desc.')';
}
$log->save();
}
}
@@ -0,0 +1,44 @@
<?php
// +----------------------------------------------------------------------
// | likeshop开源商城系统
// +----------------------------------------------------------------------
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
// | gitee下载:https://gitee.com/likeshop_gitee
// | github下载:https://github.com/likeshop-github
// | 访问官网:https://www.likeshop.cn
// | 访问社区:https://home.likeshop.cn
// | 访问手册:http://doc.likeshop.cn
// | 微信公众号:likeshop技术社区
// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
// | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
// | 禁止对系统程序代码以任何目的,任何形式的再发布
// | likeshop团队版权所有并拥有最终解释权
// +----------------------------------------------------------------------
// | author: likeshop.cn.team
// +----------------------------------------------------------------------
namespace app\common\logic;
use app\common\server\AliPayServer;
class AliPayLogic
{
//支付宝app支付
public static function appPay($order)
{
$data = [
'body'=>'商品简述',
'subject'=>'商品名',
'out_trade_no'=> $order['sn'],
'timeout_express'=>'30m',
'total_amount'=> $order['order_amount'],
'product_code'=>'FAST_INSTANT_TRADE_PAY'
];
$notify_url = 'http://tp.test/api/index/notify';
$alipay = new AliPayServer();
return $alipay->appAlipay($data, $notify_url);
}
}
@@ -0,0 +1,96 @@
<?php
// +----------------------------------------------------------------------
// | likeshop开源商城系统
// +----------------------------------------------------------------------
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
// | gitee下载:https://gitee.com/likeshop_gitee
// | github下载:https://github.com/likeshop-github
// | 访问官网:https://www.likeshop.cn
// | 访问社区:https://home.likeshop.cn
// | 访问手册:http://doc.likeshop.cn
// | 微信公众号:likeshop技术社区
// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
// | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
// | 禁止对系统程序代码以任何目的,任何形式的再发布
// | likeshop团队版权所有并拥有最终解释权
// +----------------------------------------------------------------------
// | author: likeshop.cn.team
// +----------------------------------------------------------------------
namespace app\common\logic;
use think\Db;
class CouponLogic {
public static function couponClose($user_id = ''){
$coupon_list = Db::name('coupon')
->where(['del'=>0])
->column('id,use_time_type,use_time_start,use_time_end,use_time','id');
$coupon_ids = array_keys($coupon_list);
$where[] = ['coupon_id','in',$coupon_ids];
$where[] = ['status','in',0];
if($user_id){
$where[] = ['user_id','=',$user_id];
}
$user_coupon_list = Db::name('coupon_list')
->where(['coupon_id'=>$coupon_ids,'status'=>0])
->field('id,coupon_id,create_time')
->order('id asc')
->select();
$now = time();
$update_data = [];
foreach ($user_coupon_list as $coupon_item){
$coupon = $coupon_list[$coupon_item['coupon_id']] ?? [];
if($coupon){
//用券时间类型:1-固定时间;2-领券当天起;3-领券次日起
switch ($coupon['use_time_type']){
case 1:
if($now > $coupon['use_time_end']){
$update_data[] = $coupon_item['id'];
}
break;
case 2:
$daytime = strtotime(date("Y-m-d",$coupon_item['create_time'])) + 86400 * $coupon['use_time'];
if($now > $daytime){
$update_data[] = $coupon_item['id'];
}
break;
case 3:
$day = $coupon['use_time'] + 2;
$daytime = strtotime(date("Y-m-d",$coupon_item['create_time'])) + 86400 * $day;
if($now > $daytime){
$update_data[] = $coupon_item['id'];
}
}
}
}
if($update_data){
Db::name('coupon_list')->where(['id'=>$update_data])->update(['status'=>2,'update_time'=>$now]);
}
}
/**
* Desc: 使用优惠券
* @param $coupon_list_id
* @param $order_id
* @throws \think\Exception
* @throws \think\exception\PDOException
*/
public static function handleCouponByOrder($coupon_list_id, $order_id)
{
$update_coupon = [
'status' => 1,
'use_time' => time(),
'order_id' => $order_id,
'update_time' => time(),
];
Db::name('coupon_list')
->where('id', $coupon_list_id)
->update($update_coupon);
}
}
@@ -0,0 +1,60 @@
<?php
// +----------------------------------------------------------------------
// | likeshop开源商城系统
// +----------------------------------------------------------------------
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
// | gitee下载:https://gitee.com/likeshop_gitee
// | github下载:https://github.com/likeshop-github
// | 访问官网:https://www.likeshop.cn
// | 访问社区:https://home.likeshop.cn
// | 访问手册:http://doc.likeshop.cn
// | 微信公众号:likeshop技术社区
// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
// | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
// | 禁止对系统程序代码以任何目的,任何形式的再发布
// | likeshop团队版权所有并拥有最终解释权
// +----------------------------------------------------------------------
// | author: likeshop.cn.team
// +----------------------------------------------------------------------
namespace app\common\logic;
use app\common\model\Distribution;
use app\common\model\DistributionLevel;
use app\common\server\ConfigServer;
/**
* 分销基础信息逻辑层
* Class DistributionLogic
* @package app\common\logic
*/
class DistributionLogic
{
/**
* @notes 添加分销基础信息记录
* @param $userId
* @author Tab
*/
public static function add($userId)
{
// 默认分销会员等级
$defaultLevelId = DistributionLevel::where('is_default', 1)->value('id');
// 分销会员开通方式
$apply_condition = ConfigServer::get('distribution', 'apply_condition', 2);
$isDistribution = $apply_condition == 1 ? 1 : 0;
$data = [
'user_id' => $userId,
'level_id' => $defaultLevelId,
'is_distribution' => $isDistribution,
'is_freeze' => 0,
'remark' => '',
];
if($isDistribution) {
// 成为分销会员时间
$data['distribution_time'] = time();
}
Distribution::create($data);
}
}
@@ -0,0 +1,265 @@
<?php
// +----------------------------------------------------------------------
// | likeshop开源商城系统
// +----------------------------------------------------------------------
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
// | gitee下载:https://gitee.com/likeshop_gitee
// | github下载:https://github.com/likeshop-github
// | 访问官网:https://www.likeshop.cn
// | 访问社区:https://home.likeshop.cn
// | 访问手册:http://doc.likeshop.cn
// | 微信公众号:likeshop技术社区
// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
// | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
// | 禁止对系统程序代码以任何目的,任何形式的再发布
// | likeshop团队版权所有并拥有最终解释权
// +----------------------------------------------------------------------
// | author: likeshop.cn.team
// +----------------------------------------------------------------------
namespace app\common\logic;
use app\common\model\DistributionGoods;
use app\common\model\DistributionLevel;
use app\common\model\DistributionOrderGoods;
use app\common\model\Order;
use app\common\model\OrderGoods;
use app\common\model\User;
use app\common\server\ConfigServer;
class DistributionOrderGoodsLogic extends LogicBase
{
/**
* @notes 生成分销订单
* @param $order_id
* @param $user_id
* @author Tab
*/
public static function add($orderId)
{
// 获取分销配置
$distributionConfig = [
'is_open' => ConfigServer::get('distribution', 'is_open', 0),
'level' => ConfigServer::get('distribution', 'level', 2),
];
if(!$distributionConfig['is_open']) {
return false;
}
// 用户信息
$order = Order::where('id', $orderId)->findOrEmpty()->toArray();
$userInfo = self::userInfo($order['user_id']);
// 订单信息
$orderInfo = self::orderInfo($orderId);
// 遍历子订单
foreach($orderInfo as $item) {
// 判断商品是否参与分销
$goodsDistribution = self::checkGoodsDistribution($item['goods_id']);
if(empty($goodsDistribution) || !$goodsDistribution['is_distribution']) {
// 商品未参与分销
continue;
}
// 分销层级
switch($distributionConfig['level'])
{
case 1: // 一级分销
self::firstLevelCommission($userInfo, $item, $goodsDistribution);
break;
case 2: // 一级、二级分销
self::firstLevelCommission($userInfo, $item, $goodsDistribution);
self::secondLevelCommission($userInfo, $item, $goodsDistribution);
break;
}
}
}
/**
* @notes 用户信息
* @param $userId
* @return mixed
* @author Tab
*/
public static function userInfo($userId)
{
$userInfo = User::alias('u')
->leftJoin('distribution d', 'd.user_id = u.id')
->field('u.id,u.nickname,u.first_leader,u.second_leader,d.level_id,d.is_distribution,d.is_freeze')
->where('u.id', $userId)
->findOrEmpty()
->toArray();
return $userInfo;
}
/**
* @notes 订单信息
* @param $orderId
* @return mixed
* @author Tab
*/
public static function orderInfo($orderId)
{
$orderInfo = OrderGoods::alias('og')
->leftJoin('order o', 'o.id = og.order_id')
->field('og.id as order_goods_id,og.order_id,og.goods_id,og.item_id,og.goods_num,og.total_pay_price,o.user_id')
->where('og.order_id', $orderId)
->select()
->toArray();
return $orderInfo;
}
/**
* @notes 校验商品是否参与分销
* @param $goodsId
* @return array
* @author Tab
*/
public static function checkGoodsDistribution($goodsId)
{
$distributionGoods = DistributionGoods::field('goods_id,item_id,level_id,first_ratio,second_ratio,is_distribution,rule')
->where('goods_id', $goodsId)
->select()
->toArray();
if(empty($distributionGoods)) {
return [];
}
return [
'goods_id' => $distributionGoods[0]['goods_id'],
'is_distribution' => $distributionGoods[0]['is_distribution'],
'rule' => $distributionGoods[0]['rule']
];
}
/**
* @notes 一级分佣
* @param $userInfo
* @param $item
* @param $goodsDistribution
* @return false
* @author Tab
*/
public static function firstLevelCommission($userInfo, $item, $goodsDistribution)
{
if(!$userInfo['first_leader']) {
// 没有上级,无需分佣
return false;
}
$firstLeaderInfo = self::userInfo($userInfo['first_leader']);
if(!$firstLeaderInfo['is_distribution'] || $firstLeaderInfo['is_freeze']) {
// 上级不是分销会员 或 分销资格已冻结
return false;
}
$ratioArr = self::getRatio($goodsDistribution, $item, $firstLeaderInfo);
$firstLeaderInfo['ratio'] = $ratioArr['first_ratio'];
$firstLeaderInfo['level'] = 1;
self::addDistributionOrderGoods($item, $firstLeaderInfo);
}
/**
* @notes 获取分佣比例
* @param $goodsDistribution
* @param $item
* @param $userInfo
* @return array
* @author Tab
*/
public static function getRatio($goodsDistribution, $item, $userInfo)
{
// 按分销会员等级对应的比例
if($goodsDistribution['rule'] == 1) {
$ratioArr = DistributionLevel::field('first_ratio,second_ratio')
->where('id', $userInfo['level_id'])
->findOrEmpty()
->toArray();
return $ratioArr;
}
// 单独设置的比例
if($goodsDistribution['rule'] == 2) {
$ratioArr = DistributionGoods::field('first_ratio,second_ratio')
->where([
'goods_id' => $item['goods_id'],
'item_id' => $item['item_id'],
'level_id' => $userInfo['level_id']
])
->findOrEmpty()
->toArray();
return $ratioArr;
}
}
/**
* @notes 二级分佣
* @param $userInfo
* @param $item
* @param $goodsDistribution
* @return false
* @author Tab
*/
public static function secondLevelCommission($userInfo, $item, $goodsDistribution)
{
if(!$userInfo['second_leader']) {
// 没有上上级,无需分佣
return false;
}
$secondLeaderInfo = self::userInfo($userInfo['second_leader']);
if(!$secondLeaderInfo['is_distribution'] || $secondLeaderInfo['is_freeze']) {
// 上上级不是分销会员 或 分销资格已冻结
return false;
}
$ratioArr = self::getRatio($goodsDistribution, $item, $secondLeaderInfo);
$secondLeaderInfo['ratio'] = $ratioArr['second_ratio'];
$secondLeaderInfo['level'] = 2;
self::addDistributionOrderGoods($item, $secondLeaderInfo);
}
/**
* @notes 生成分销订单
* @param $item
* @param $userInfo
* @return false
* @author Tab
*/
public static function addDistributionOrderGoods($item, $userInfo)
{
$earnings = 0;
$earnings = self::calByPaymentAmount($item, $userInfo);
if($earnings < 0.01) {
return false;
}
$data = [
'sn' => createSn('distribution_order_goods', 'sn'),
'user_id' => $userInfo['id'],
'real_name' => $userInfo['nickname'],
'level_id' => $userInfo['level_id'],
'level' => $userInfo['level'],
'ratio' => $userInfo['ratio'],
'order_id' => $item['order_id'],
'order_goods_id' => $item['order_goods_id'],
'goods_num' => $item['goods_num'],
'money' => $earnings,
'status' => 1,
'create_time' => time(),
];
DistributionOrderGoods::create($data);
}
/**
* @notes 根据商品实际支付金额计算佣金
* @param $item
* @param $userInfo
* @return float
* @author Tab
*/
public static function calByPaymentAmount($item, $userInfo)
{
$earnings = round(($item['total_pay_price'] * $userInfo['ratio'] / 100), 2);
return $earnings;
}
}
@@ -0,0 +1,179 @@
<?php
// +----------------------------------------------------------------------
// | likeshop开源商城系统
// +----------------------------------------------------------------------
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
// | gitee下载:https://gitee.com/likeshop_gitee
// | github下载:https://github.com/likeshop-github
// | 访问官网:https://www.likeshop.cn
// | 访问社区:https://home.likeshop.cn
// | 访问手册:http://doc.likeshop.cn
// | 微信公众号:likeshop技术社区
// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
// | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
// | 禁止对系统程序代码以任何目的,任何形式的再发布
// | likeshop团队版权所有并拥有最终解释权
// +----------------------------------------------------------------------
// | author: likeshop.cn.team
// +----------------------------------------------------------------------
namespace app\common\logic;
use think\Db;
class FileCateLogic
{
/**
* Desc: 详情
* @param $id
* @return array|\PDOStatement|string|\think\Model|null
*/
public static function info($id)
{
return Db::name('file_cate')->where(['id' => $id])->find();
}
/**
* Desc: 添加分类
* @param $post
* @return bool
*/
public static function add($post)
{
$level = 0;
if ($post['pid']) {
$level = Db::name('file_cate')
->where(['id' => $post['pid']])
->where(['del' => 0])
->value('level');
}
$data = [
'name' => $post['name'],
'pid' => $post['pid'],
'sort' => $post['sort'],
'level' => $level + 1,
'create_time' => time(),
'type' => 1
];
Db::name('file_cate')->insert($data);
return true;
}
/**
* Desc: 编辑分类
* @param $post
* @return bool
*/
public static function edit($post)
{
$level = 0;
$data = [
'pid' => $post['pid'],
'name' => $post['name'],
'sort' => $post['sort'],
'update_time' => time(),
];
if ($post['pid']) {
$level = Db::name('file_cate')
->where(['id' => $post['pid']])
->where(['del' => 0])
->value('level');
}
$data['level'] = $level + 1;
Db::name('file_cate')->where('id', $post['id'])->update($data);
return true;
}
/**
* Desc: 删除
* @param $id
* @return int|string
*/
public static function del($id)
{
$data = [
'del' => 1,
'update_time' => time(),
];
return Db::name('file_cate')->where(['del' => 0, 'id' => $id])->update($data);
}
/**
* Desc: 树形结构
* @return array
*/
public static function cateTree()
{
$lists = Db::name('file_cate')
->where(['del' => 0, 'type'=>1])
->order('sort')
->select();
$tree = self::cateListToTree($lists, 0);
$all = [
'id' => 0,
'field' => 'all',
'title' => '全部',
'children' => [],
];
array_unshift($tree,$all);
return $tree;
}
public static function cateListToTree($lists, $pid = 0)
{
$tree = [];
foreach ($lists as $k => $v) {
if ($v['pid'] == $pid) {
$temp['id'] = $v['id'];
$temp['field'] = 'id';
$temp['title'] = $v['name'];
$temp['children'] = self::cateListToTree($lists, $v['id']);
$temp['spread'] = true;
$tree[] = $temp;
}
}
return $tree;
}
/**
* Desc: 下拉框树状结构
* @return array
*/
public static function categoryToSelect()
{
$lists = Db::name('file_cate')
->where(['del' => 0])
->order('sort')
->select();
$tree = [];
foreach ($lists as $val) {
if ($val['pid'] != 0) {
continue;
}
$tree[$val['id']] = "|----" . $val['name'];
foreach ($lists as $val2) {
if ($val2['pid'] == $val['id']) {
$tree[$val2['id']] = "|--------" . $val2['name'];
}
}
}
return $tree;
}
}
@@ -0,0 +1,236 @@
<?php
// +----------------------------------------------------------------------
// | likeshop开源商城系统
// +----------------------------------------------------------------------
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
// | gitee下载:https://gitee.com/likeshop_gitee
// | github下载:https://github.com/likeshop-github
// | 访问官网:https://www.likeshop.cn
// | 访问社区:https://home.likeshop.cn
// | 访问手册:http://doc.likeshop.cn
// | 微信公众号:likeshop技术社区
// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
// | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
// | 禁止对系统程序代码以任何目的,任何形式的再发布
// | likeshop团队版权所有并拥有最终解释权
// +----------------------------------------------------------------------
// | author: likeshop.cn.team
// +----------------------------------------------------------------------
namespace app\common\logic;
use app\api\model\User;
use app\common\model\AccountLog;
use app\common\model\OrderGoods;
use app\common\server\ConfigServer;
use think\Db;
class IntegralLogic
{
/**
* Notes: 订单是否开启积分抵扣
* @param $order_goods
* @author 段誉(2021/4/1 11:05)
* @return bool
*/
public static function isIntegralInOrder($order_goods)
{
$integral_switch = ConfigServer::get('marketing', 'integral_deduction_status', 0);
if ($integral_switch == 0) {
return false;
}
foreach ($order_goods as $good) {
if ($good['is_integral'] != 1) {
return false;
}
}
return true;
}
/**
* Desc: 处理积分
* @param $user_id
* @param $use_integral
* @param $channel
* @param $source_id
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function handleIntegral($user_id, $use_integral, $channel, $source_id)
{
$user = User::get($user_id);
switch ($channel) {
//下单积分抵扣
case AccountLog::order_deduction_integral:
$user->user_integral = ['dec', $use_integral];
$change_type = 2;
break;
//取消订单退回积分
case AccountLog::cancel_order_refund_integral:
$user->user_integral = ['inc', $use_integral];
$change_type = 1;
break;
//下单奖励积分(每天一单)
case AccountLog::order_add_integral:
$user->user_integral = ['inc', $use_integral];
$change_type = 1;
break;
//扣除首单积分奖励(用户取消订单)
case AccountLog::deduct_order_first_integral:
$diff = $user->user_integral - $use_integral;
if ($diff < 0) {
$user->user_integral = 0;
} else {
$user->user_integral = ['dec', $use_integral];
}
$change_type = 2;
break;
//购买商品赠送积分
case AccountLog::order_goods_give_integral:
$user->user_integral = ['inc', $use_integral];
$change_type = 1;
break;
default:
return;
}
$user->save();
//更新积分记录
AccountLogLogic::AccountRecord($user_id, $use_integral, $change_type, $channel, '', $source_id);
}
/**
* Desc: 下单奖励积分(每天第一单)
* @param $user_id
* @param $order_id
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function rewardIntegral($user_id, $order_id)
{
//是否为当天第一个订单(是->奖励积分)
$check = Db::name('account_log')
->where(['user_id' => $user_id, 'source_type' => AccountLog::order_add_integral])
->whereTime('create_time', 'today')
->find();
//下单奖励开关;0-关闭;1-开启;
$order_award_integral = ConfigServer::get('marketing', 'order_award_integral', 0);
if ($order_award_integral == 0 || $check) {
return;
}
self::handleIntegral($user_id, $order_award_integral, AccountLog::order_add_integral, $order_id);
}
/**
* Notes: 扣除首单积分
* @param $user_id
* @param $order_id
* @author 段誉(2021/2/25 10:23)
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function backIntegral($user_id, $order_id)
{
$log = Db::name('account_log')
->where([
'user_id' => $user_id,
'source_type' => AccountLog::order_add_integral,
'source_id' => $order_id
])
->find();
if (!$log){
return false;
}
self::handleIntegral($user_id, $log['change_amount'], AccountLog::deduct_order_first_integral, $order_id);
return true;
}
/**
* Notes: 购买商品奖励积分
* @param $user_id
* @param $order_id
* @author 段誉(2021/4/1 11:06)
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function rewardIntegralByGoods($user_id, $order_id)
{
$goods_model = new OrderGoods();
$goods = $goods_model->alias('og')
->field('g.*,og.total_pay_price')
->join('goods g', 'g.id = og.goods_id')
->where(['order_id' => $order_id])
->select();
$get_integral = 0;//可得积分
foreach ($goods as $good) {
//赠送积分类型:0-不赠送;1-赠送固定积分;2-按比例赠送积分'
if ($good['give_integral_type'] == 0) {
continue;
}
$good['give_integral'] = empty($good['give_integral']) ? 0 : intval($good['give_integral']);
if ($good['give_integral_type'] == 1) {
$get_integral += $good['give_integral'];
}
if ($good['give_integral_type'] == 2) {
$get_integral += $good['give_integral'] * $good['total_pay_price'] / 100;
}
}
if ($get_integral <= 0) {
return;
}
//用户赠送积分
self::handleIntegral($user_id, $get_integral, AccountLog::order_goods_give_integral, $order_id);
}
/**
* Notes: 积分抵扣描述
* @param $integral_config
* @param $integral_limit
* @author 段誉(2021/5/19 18:32)
* @return string
*/
public static function getIntegralDesc($integral_config, $integral_limit)
{
if ($integral_config <= 0) {
return '积分不可抵扣';
}
$integral_desc = $integral_config.'积分可抵扣1元';
if ($integral_limit > 0) {
$integral_desc .= ',单次抵扣积分不能低于'.$integral_limit;
}
return $integral_desc;
}
}
@@ -0,0 +1,43 @@
<?php
// +----------------------------------------------------------------------
// | likeshop开源商城系统
// +----------------------------------------------------------------------
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
// | gitee下载:https://gitee.com/likeshop_gitee
// | github下载:https://github.com/likeshop-github
// | 访问官网:https://www.likeshop.cn
// | 访问社区:https://home.likeshop.cn
// | 访问手册:http://doc.likeshop.cn
// | 微信公众号:likeshop技术社区
// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
// | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
// | 禁止对系统程序代码以任何目的,任何形式的再发布
// | likeshop团队版权所有并拥有最终解释权
// +----------------------------------------------------------------------
// | author: likeshop.cn.team
// +----------------------------------------------------------------------
namespace app\common\logic;
class LogicBase
{
public static $error;
public static function dataSuccess($msg = '', $data = [], $code = 1, $show = 0)
{
return data_success($msg, $data, $code, $show);
}
public static function dataError($msg = '', $data = [], $code = 0, $show = 1)
{
return data_error($msg, $data, $code, $show);
}
public static function getError()
{
return self::$error;
}
}
@@ -0,0 +1,203 @@
<?php
// +----------------------------------------------------------------------
// | likeshop开源商城系统
// +----------------------------------------------------------------------
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
// | gitee下载:https://gitee.com/likeshop_gitee
// | github下载:https://github.com/likeshop-github
// | 访问官网:https://www.likeshop.cn
// | 访问社区:https://home.likeshop.cn
// | 访问手册:http://doc.likeshop.cn
// | 微信公众号:likeshop技术社区
// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
// | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
// | 禁止对系统程序代码以任何目的,任何形式的再发布
// | likeshop团队版权所有并拥有最终解释权
// +----------------------------------------------------------------------
// | author: likeshop.cn.team
// +----------------------------------------------------------------------
namespace app\common\logic;
use app\common\model\NoticeSetting;
use app\common\server\ConfigServer;
use app\common\server\UrlServer;
use think\Db;
class NoticeLogic
{
//添加通知记录
public static function addNoticeLog($params, $scene_info, $send_type, $content, $extra = '')
{
return Db::name('notice')->insertGetId([
'user_id' => $params['user_id'] ?? 0,
'title' => self::getTitleByScene($send_type, $scene_info),
'content' => $content,
'scene' => $params['scene'],
'receive_type' => self::getReceiveTypeByScene($params['scene']),
'send_type' => $send_type,
'extra' => $extra,
'create_time' => time()
]);
}
//更新通知记录
public static function updateNotice($notice_id, $extra)
{
return Db::name('notice')
->where('id', $notice_id)
->update(['extra' => $extra]);
}
//格式化消息内容(替换文本)
public static function contentFormat($content, $params)
{
foreach ($params as $k => $v) {
$search_replace = '{'.$k.'}';
$content = str_replace($search_replace, $v, $content);
}
return $content;
}
//根据不同发送类型获取标题
public static function getTitleByScene($send_type, $scene_info)
{
$title = '';
switch ($send_type) {
case NoticeSetting::SYSTEM_NOTICE:
$title = $scene_info['system_notice']['title'] ?? '';
break;
case NoticeSetting::SMS_NOTICE:
$title = '';
break;
case NoticeSetting::OA_NOTICE:
$title = $scene_info['oa_notice']['name'] ?? '';
break;
case NoticeSetting::MNP_NOTICE:
$title = $scene_info['mnp_notice']['name'] ?? '';
break;
}
return $title;
}
//根据场景返回当前接收对象
public static function getReceiveTypeByScene($scene)
{
if (in_array($scene, NoticeSetting::NOTICE_PLATFORM_SCENE)) {
return NoticeSetting::NOTICE_PLATFORM;
}
if (in_array($scene, NoticeSetting::NOTICE_USER_SCENE)) {
return NoticeSetting::NOTICE_USER;
}
if (in_array($scene, NoticeSetting::NOTICE_OTHER_SCENE)) {
return NoticeSetting::NOTICE_OTHER;
}
}
//================================================================================================
//消息主页
public static function index($user_id)
{
//最新系统消息
$server = Db::name('notice')
->where('scene', '<>', NoticeSetting::GET_EARNINGS_NOTICE)
->where(['user_id' => $user_id, 'send_type' => NoticeSetting::SYSTEM_NOTICE])
->order('id desc')
->find();
//最新收益通知
$earning = Db::name('notice')
->where('scene', NoticeSetting::GET_EARNINGS_NOTICE)
->where(['user_id' => $user_id, 'send_type' => NoticeSetting::SYSTEM_NOTICE])
->order('id desc')
->find();
$data['system'] = [
'title' => '系统通知',
'content' => $server['content'] ?? '暂无系统消息',
'img' => UrlServer::getFileUrl(ConfigServer::get('website', 'system_notice')),
'type' => 'system',
];
$data['earning'] = [
'title' => '收益通知',
'content' => $earning['content'] ?? '暂无收益消息',
'img' => UrlServer::getFileUrl(ConfigServer::get('website', 'earning_notice')),
'type' => 'earning',
];
$res = array_values($data);
return $res;
}
//消息列表
public static function lists($user_id, $type, $page, $size)
{
$where = [];
$where[] = ['user_id', '=', $user_id];
$where[] = ['send_type', '=', NoticeSetting::SYSTEM_NOTICE];
if ($type == 'earning') {
$where[] = ['scene', '=', NoticeSetting::GET_EARNINGS_NOTICE];
}else{
$where[] = ['scene', '<>', NoticeSetting::GET_EARNINGS_NOTICE];
}
$count = Db::name('notice')->where($where)->count();
$lists = Db::name('notice')
->where($where)
->order('id desc')
->page($page, $size)
->select();
foreach ($lists as $k => $item) {
$lists[$k]['create_time'] = date('Y-m-d H:i:s', $item['create_time']);
$lists[$k]['type'] = NoticeSetting::getSceneDesc(($item['scene']));
}
$data = [
'list' => $lists,
'page' => $page,
'size' => $size,
'count' => $count,
'more' => is_more($count, $page, $size)
];
self::setRead($where);
return $data;
}
//更新为已读
public static function setRead($where)
{
//进入列表后全部已读
Db::name('notice')
->where($where)
->where('read','<>', 1)
->update(['read' => 1]);
}
//是否有未读的消息
public static function unRead($user_id)
{
$un_read = Db::name('notice')
->where(['user_id' => $user_id, 'read' => 0])
->where(['send_type' => NoticeSetting::SYSTEM_NOTICE])
->find();
if ($un_read){
return true;
}
return false;
}
}
@@ -0,0 +1,191 @@
<?php
// +----------------------------------------------------------------------
// | likeshop开源商城系统
// +----------------------------------------------------------------------
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
// | gitee下载:https://gitee.com/likeshop_gitee
// | github下载:https://github.com/likeshop-github
// | 访问官网:https://www.likeshop.cn
// | 访问社区:https://home.likeshop.cn
// | 访问手册:http://doc.likeshop.cn
// | 微信公众号:likeshop技术社区
// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
// | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
// | 禁止对系统程序代码以任何目的,任何形式的再发布
// | likeshop团队版权所有并拥有最终解释权
// +----------------------------------------------------------------------
// | author: likeshop.cn.team
// +----------------------------------------------------------------------
namespace app\common\logic;
use app\api\logic\SeckillLogic;
use app\common\model\AfterSale;
use app\common\model\Order;
use app\common\model\OrderGoods;
use app\common\model\Pay;
use app\common\server\ConfigServer;
use think\Db;
use think\facade\Hook;
/**
* 订单商品逻辑
* Class OrderGoodsLogic
* @package app\common\logic
*/
class OrderGoodsLogic
{
//返回订单库存,销量
public static function backStock($order_goods, $pay_status)
{
$deduct_type = ConfigServer::get('trading', 'deduct_type', 1);
//支付后扣减
if ($deduct_type == 0 && $pay_status == Pay::UNPAID) {
return;
}
foreach ($order_goods as $good) {
//回退库存,回退规格库存,减少商品销量
Db::name('goods')
->where('id', $good['goods_id'])
->update([
// 'sales_sum' => Db::raw("sales_sum-" . $good['goods_num']),
'stock' => Db::raw('stock+' . $good['goods_num'])
]);
//补充规格表库存
Db::name('goods_item')
->where('id', $good['item_id'])
->setInc('stock', $good['goods_num']);
}
}
//下单扣除订单库存
public static function decStock($goods)
{
$seckill_data = SeckillLogic::getSeckillGoods();
$seckill = $seckill_data['seckill'];
$seckill_goods = $seckill_data['seckill_goods'];
$goods_ids = [];
foreach ($goods as $k1 => $good) {
$item_id = $good['item_id'];
//扣除库存,扣除规格库存,增加商品销量
Db::name('goods')
->where('id', $good['goods_id'])
->update([
'sales_sum' => Db::raw("sales_sum+" . $good['goods_num']),
'stock' => Db::raw('stock-' . $good['goods_num'])
]);
//扣除规格表库存
Db::name('goods_item')
->where('id', $item_id)
->setDec('stock', $good['goods_num']);
//秒杀商品增加销量
if (isset($seckill_goods[$item_id])){
$seckill_goods_id = $seckill_goods[$item_id]['seckill_goods_id'];
Db::name('seckill_goods')
->where('id', $seckill_goods_id)
->update([
'sales_sum' => Db::raw("sales_sum+" . $good['goods_num']),
'update_time' => time()
]);
}
$goods_ids[] = $good['goods_id'];
}
//下架商品总库存为0的商品
if (!empty($goods_ids)){
self::outGoods($goods_ids);
}
}
/**
* Notes: 下单后下架商品总库存为0的商品
* @param $goods_id
* @author 段誉(2021/3/19 16:19)
* @return bool
*/
public static function outGoods($goods_ids)
{
try{
$goods = Db::name('goods')
->field('id, stock')
->where('id', 'in', $goods_ids)
->select();
if (empty($goods)){
return true;
}
$need_handle_ids = [];
foreach ($goods as $good) {
if ($good['stock'] <= 0) {
$need_handle_ids[] = $good['id'];
}
}
if (empty($need_handle_ids)){
return true;
}
//下架订单商品中 商品总库存已为0的商品
Db::name('goods')->where('id', 'in', $need_handle_ids)->update(['status' => 0]);
// 下架或删除商品,更新商品收藏
Hook::listen('update_collect', ['goods_id' => $need_handle_ids]);
} catch (\Exception $e) {}
}
/**
* @notes 获取订单商品 退款运费
* @return integer|float
* @author lbzy
* @datetime 2023-06-26 09:20:21
*/
static function getRefundExpressMoney($id)
{
$orderGoods = OrderGoods::find($id);
$order = Order::find($orderGoods['order_id'] ?? 0);
// 不是待发货 不退运费
if (empty($order['id']) || $order['order_status'] != Order::STATUS_WAIT_DELIVERY) {
return 0;
}
$after_sales = AfterSale::where('order_id', $order['id'])->select()->toArray();
$aids = [];
foreach ($after_sales as $after_sale) {
if (! in_array($after_sale['order_goods_id'], $aids)) {
$aids[] = $after_sale['order_goods_id'];
}
}
$orderGoodsList = OrderGoods::where('order_id', $order['id'])->select()->toArray();
if (count($aids) != count($orderGoodsList)) {
if (in_array($id, $aids)) {
return 0;
} else {
// 没有记录,是否是最后一个订单商品
return count($aids) == (count($orderGoodsList) - 1) ? $order['shipping_price'] : 0;
}
}
// 有记录,是否是在最后申请的
return $aids[count($aids) - 1] == $id ? $order['shipping_price'] : 0;
}
}
@@ -0,0 +1,50 @@
<?php
// +----------------------------------------------------------------------
// | likeshop开源商城系统
// +----------------------------------------------------------------------
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
// | gitee下载:https://gitee.com/likeshop_gitee
// | github下载:https://github.com/likeshop-github
// | 访问官网:https://www.likeshop.cn
// | 访问社区:https://home.likeshop.cn
// | 访问手册:http://doc.likeshop.cn
// | 微信公众号:likeshop技术社区
// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
// | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
// | 禁止对系统程序代码以任何目的,任何形式的再发布
// | likeshop团队版权所有并拥有最终解释权
// +----------------------------------------------------------------------
// | author: likeshop.cn.team
// +----------------------------------------------------------------------
namespace app\common\logic;
use app\common\model\OrderLog;
/**
* 订单记录日志
* Class OrderLogLogic
* @package app\common\logic
*/
class OrderLogLogic
{
public static function record($type, $channel, $order_id, $handle_id, $content, $desc = '')
{
if (empty($content)) {
return true;
}
$log = new OrderLog();
$log->type = $type;
$log->order_id = $order_id;
$log->channel = $channel;
$log->handle_id = $handle_id;
$log->content = OrderLog::getLogDesc($content);
$log->create_time = time();
if ($desc != '') {
$log->content = OrderLog::getLogDesc($content) . '(' . $desc . ')';
}
$log->save();
}
}
@@ -0,0 +1,361 @@
<?php
// +----------------------------------------------------------------------
// | likeshop开源商城系统
// +----------------------------------------------------------------------
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
// | gitee下载:https://gitee.com/likeshop_gitee
// | github下载:https://github.com/likeshop-github
// | 访问官网:https://www.likeshop.cn
// | 访问社区:https://home.likeshop.cn
// | 访问手册:http://doc.likeshop.cn
// | 微信公众号:likeshop技术社区
// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
// | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
// | 禁止对系统程序代码以任何目的,任何形式的再发布
// | likeshop团队版权所有并拥有最终解释权
// +----------------------------------------------------------------------
// | author: likeshop.cn.team
// +----------------------------------------------------------------------
namespace app\common\logic;
use app\api\logic\DistributionLogic;
use app\api\model\Order;
use app\common\model\AccountLog;
use app\common\model\Order as CommonOrder;
use app\common\model\OrderGoods;
use app\common\model\OrderLog;
use app\common\model\Pay;
use app\common\model\User;
use app\common\server\AliPayServer;
use app\common\server\WeChatPayServer;
use app\common\server\WeChatServer;
use think\Db;
use think\Exception;
use think\facade\Hook;
use think\facade\Log;
/**
* 订单退款逻辑
* Class OrderRefundLogic
* @package app\common\logic
*/
class OrderRefundLogic
{
/**
* Notes: 取消订单
* @param $order_id
* @param int $handle_type
* @param int $handle_id
* @author 段誉(2021/1/28 15:23)
* @return Order
*/
public static function cancelOrder($order_id, $handle_type = OrderLog::TYPE_SYSTEM, $handle_id = 0)
{
//更新订单状态
$order = Order::get($order_id);
$order->order_status = CommonOrder::STATUS_CLOSE;
$order->update_time = time();
$order->cancel_time = time();
$order->save();
//取消订单后操作
Hook::listen('cancel_order', ['order_id' => $order_id, 'handle_id' => $handle_id, 'handle_type' => $handle_type]);
return $order;
}
/**
* @notes 处理订单退款(事务在取消订单逻辑处)
* @param $order
* @param $order_amount
* @param $refund_amount
* @return bool
* @throws Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
* @author 段誉
* @date 2021/12/20 14:48
*/
public static function refund($order, $order_amount, $refund_amount)
{
// 退款记录
$refund_id = self::addRefundLog($order, $order_amount, $refund_amount);
// 退款金额为0
if ($refund_amount <= 0) {
return false;
}
switch ($order['pay_way']) {
// 余额退款
case Pay::BALANCE_PAY:
self::balancePayRefund($order, $refund_amount);
break;
// 微信退款
case Pay::WECHAT_PAY:
self::wechatPayRefund($order, $refund_id);
break;
// 支付宝退款
case Pay::ALI_PAY:
self::aliPayRefund($order, $refund_id);
break;
}
return true;
}
/**
* Notes: 微信支付退款
* @param $order (订单信息)
* @param $refund_id (退款记录id) 
* @author 段誉(2021/1/27 16:04)
* @throws Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
* @throws \think\exception\PDOException
*/
public static function wechatPayRefund($order, $refund_id)
{
$config = WeChatServer::getPayConfigBySource($order['order_source'])['config'];
if (empty($config)) {
throw new Exception('请联系管理员设置微信相关配置!');
}
if (!isset($config['cert_path']) || !isset($config['key_path'])) {
throw new Exception('请联系管理员设置微信证书!');
}
if (!file_exists($config['cert_path']) || !file_exists($config['key_path'])) {
throw new Exception('微信证书不存在,请联系管理员!');
}
$refund_log = Db::name('order_refund')->where(['id' => $refund_id])->find();
$data = [
'transaction_id' => $order['transaction_id'],
'refund_sn' => $refund_log['refund_sn'],
'total_fee' => intval(strval($refund_log['order_amount'] * 100)),//订单金额,单位为分
'refund_fee' => intval(strval($refund_log['refund_amount'] * 100)),//退款金额
];
$result = WeChatPayServer::refund($config, $data);
if (isset($result['return_code']) && $result['return_code'] == 'FAIL') {
throw new Exception($result['return_msg']);
}
if (isset($result['err_code_des'])) {
throw new Exception($result['err_code_des']);
}
if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS') {
$update_data = [
'wechat_refund_id' => $result['refund_id'] ?? 0,
'refund_msg' => json_encode($result, JSON_UNESCAPED_UNICODE),
];
//更新退款日志记录
Db::name('order_refund')->where(['id' => $refund_id])->update($update_data);
} else {
throw new Exception('微信支付退款失败');
}
}
/**
* Notes: 支付宝退款
* @param $order
* @param $refund_id
* @author 段誉(2021/3/23 15:48)
* @throws Exception
* @throws \think\exception\PDOException
*/
public static function aliPayRefund($order, $refund_id)
{
$refund_log = Db::name('order_refund')->where(['id' => $refund_id])->find();
$result = (new AliPayServer())->refund($order['order_sn'], $refund_log['refund_amount'], [ 'out_request_no' => $refund_log['refund_sn'] ]);
$result = (array) $result;
if ($result['code'] == '10000' && $result['msg'] == 'Success' && $result['fundChange'] == 'Y') {
//更新退款日志记录
$update_data = ['refund_msg' => json_encode($result['httpBody'], JSON_UNESCAPED_UNICODE)];
Db::name('order_refund')->where(['id' => $refund_id])->update($update_data);
} else {
Log::write($result, 'alipay_refund_error');
throw new Exception('支付宝退款失败');
}
}
/**
* Notes: 增加退款记录
* @param $order
* @param $order_amount
* @param $refund_amount
* @param string $result_msg
* @author 段誉(2021/1/28 15:23)
* @return int|string
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function addRefundLog($order, $order_amount, $refund_amount, $result_msg = '退款成功')
{
$data = [
'order_id' => $order['id'],
'user_id' => $order['user_id'],
'refund_sn' => createSn('order_refund', 'refund_sn'),
'order_amount' => $order_amount,
'refund_amount' => $refund_amount,
'transaction_id' => $order['transaction_id'],
'create_time' => time(),
'refund_status' => 1,
'refund_at' => time(),
'refund_msg' => json_encode($result_msg, JSON_UNESCAPED_UNICODE),
];
return Db::name('order_refund')->insertGetId($data);
}
/**
* Notes: 取消订单,退款后更新订单和订单商品信息
* @param $order
* @author 段誉(2021/1/28 14:21)
* @throws Exception
* @throws \think\exception\PDOException
*/
public static function cancelOrderRefundUpdate($order)
{
//订单商品=>标记退款成功状态
Db::name('order_goods')
->where(['order_id' => $order['id']])
->update(['refund_status' => OrderGoods::REFUND_STATUS_SUCCESS]);
//更新订单支付状态为已退款
Db::name('order')->where(['id' => $order['id']])->update([
'pay_status' => Pay::REFUNDED,
'refund_status' => 2,//订单退款状态; 0-未退款;1-部分退款;2-全部退款
'refund_amount' => $order['order_amount'],
]);
}
/**
* Notes:售后退款更新订单或订单商品状态
* @param $order
* @param $order_goods_id
* @author 段誉(2021/1/28 15:22)
*/
public static function afterSaleRefundUpdate($order, $order_goods_id, $admin_id = 0)
{
$order_goods = OrderGoods::get(['id' => $order_goods_id]);
$order_goods->refund_status = OrderGoods::REFUND_STATUS_SUCCESS;//退款成功
$order_goods->save();
//更新订单状态
$order = \app\common\model\Order::get(['id' => $order['id']]);
// $order->pay_status = Pay::REFUNDED;
$order->refund_amount += $order_goods['total_pay_price'];//退款金额 + 以前的退款金额
$order->refund_status = 1;//退款状态:0-未退款;1-部分退款;2-全部退款
//如果订单商品已全部退款
if (self::checkOrderGoods($order['id'])) {
$order->order_status = CommonOrder::STATUS_CLOSE;
$order->refund_status = 2;
OrderLogLogic::record(
OrderLog::TYPE_SHOP,
OrderLog::SYSTEM_CANCEL_ORDER,
$order['id'],
$admin_id,
OrderLog::SYSTEM_CANCEL_ORDER
);
}
$order->save();
//更新相关分佣订单为已失效
DistributionLogic::setFailByAfterSale($order_goods_id);
}
//订单内商品是否已全部
public static function checkOrderGoods($order_id)
{
$order_goods = OrderGoods::where('order_id', $order_id)->select();
if (empty($order_goods)) {
return false;
}
foreach ($order_goods as $item) {
if ($item['refund_status'] != OrderGoods::REFUND_STATUS_SUCCESS) {
return false;
}
}
return true;
}
/**
* Notes: 余额退款
* @param $order
* @param $refund_amount
* @author 段誉(2021/1/28 15:24)
* @return bool
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function balancePayRefund($order, $refund_amount)
{
$user = User::get($order['user_id']);
$user->user_money = ['inc', $refund_amount];
$user->save();
AccountLogLogic::AccountRecord(
$order['user_id'],
$refund_amount,
1,
AccountLog::cancel_order_refund,
'',
$order['id'],
$order['order_sn']
);
return true;
}
/**
* Notes: 退款失败增加错误记录
* @param $order
* @param $err_msg
* @author 段誉(2021/1/28 15:24)
* @return int|string
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\ModelNotFoundException
* @throws \think\exception\DbException
*/
public static function addErrorRefund($order, $err_msg)
{
$refund_data = [
'order_id' => $order['id'],
'user_id' => $order['user_id'],
'refund_sn' => createSn('order_refund', 'refund_sn'),
'order_amount' => $order['order_amount'],//订单应付金额
'refund_amount' => $order['order_amount'],//订单退款金额
'transaction_id' => $order['transaction_id'],
'create_time' => time(),
'refund_status' => 2,
'refund_msg' => json_encode($err_msg, JSON_UNESCAPED_UNICODE),
];
return Db::name('order_refund')->insertGetId($refund_data);
}
}
@@ -0,0 +1,203 @@
<?php
// +----------------------------------------------------------------------
// | likeshop开源商城系统
// +----------------------------------------------------------------------
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
// | gitee下载:https://gitee.com/likeshop_gitee
// | github下载:https://github.com/likeshop-github
// | 访问官网:https://www.likeshop.cn
// | 访问社区:https://home.likeshop.cn
// | 访问手册:http://doc.likeshop.cn
// | 微信公众号:likeshop技术社区
// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
// | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
// | 禁止对系统程序代码以任何目的,任何形式的再发布
// | likeshop团队版权所有并拥有最终解释权
// +----------------------------------------------------------------------
// | author: likeshop.cn.team
// +----------------------------------------------------------------------
namespace app\common\logic;
use app\admin\logic\DistributionLevelLogic;
use app\api\logic\GoodsLogic;
use app\api\logic\OrderLogic;
use app\api\logic\TeamLogic;
use app\common\model\{AccountLog, Footprint, MessageScene_, NoticeSetting, OrderLog, User, Pay, Order, OrderTrade};
use app\common\server\ConfigServer;
use app\common\server\DistributionServer;
use think\Db;
use think\Exception;
use think\facade\Hook;
use think\facade\Log;
/**
* 支付成功后处理订单状态
* Class PayNotifyLogic
* @package app\api\logic
*/
class PayNotifyLogic
{
public static function handle($action, $order_sn, $extra = [])
{
Db::startTrans();
try {
self::$action($order_sn, $extra);
Db::commit();
return true;
} catch (Exception $e) {
Db::rollback();
$record = [
__CLASS__, __FUNCTION__, $e->getFile(), $e->getLine(), $e->getMessage()
];
Log::record(implode('-', $record));
return $e->getMessage();
}
}
//下单回调
private static function order($order_sn, $extra = [])
{
$time = time();
$order_model = new Order();
$order = $order_model
->with('order_goods')
->where('order_sn',$order_sn)
->find();
//增加会员消费累计额度
$user = User::get($order['user_id']);
$user->total_order_amount = ['inc', $order['order_amount']];
$user->save();
// 更改订单状态
$orderData = [
'pay_status' => Pay::ISPAID,
'pay_time' => $time,
'order_status' => Order::STATUS_WAIT_DELIVERY,
'transaction_id' => $extra['transaction_id'] ?? '',
];
if (! Order::where('id', $order->id)->where('pay_status', Pay::UNPAID)->update($orderData)) {
throw new \Exception('订单更改状态失败');
}
//扣除库存
$deduct_type = ConfigServer::get('trading','deduct_type', 1);
if ($deduct_type == 0) {
//扣除库存,增加销量
OrderGoodsLogic::decStock($order['order_goods']);
}
//订单日志
OrderLogLogic::record(
OrderLog::TYPE_USER,
OrderLog::USER_PAID_ORDER,
$order['id'],
$user['id'],
OrderLog::USER_PAID_ORDER
);
//拼团订单,更新拼团信息
if ($order['order_type'] == Order::TEAM_ORDER){
TeamLogic::updateTeam($order['id']);
}
// 普通订单参与分销
if ($order['order_type'] == Order::NORMAL_ORDER){
// 生成分销订单
DistributionOrderGoodsLogic::add($order['id']);
// 更新分销会员等级
DistributionLevelLogic::updateDistributionLevel($order['user_id']);
}
//下单奖励积分(每天首单)
IntegralLogic::rewardIntegral($user['id'], $order['id']);
//发送通知
Hook::listen('notice', [
'user_id' => $user['id'],
'order_id' => $order['id'],
'scene' => NoticeSetting::ORDER_PAY_NOTICE,
]);
//短信通知
Hook::listen('sms_send', [
'key' => NoticeSetting::ORDER_PAY_NOTICE,
'mobile' => $order->mobile,
'user_id' => $user->id,
'params' => [
'nickname' => $user->nickname,
'order_sn' => $order->order_sn,
'order_amount' => $order->order_amount,
'time' => date('Y-m-d H:i', strtotime($order->create_time)),
'total_num' => $order->total_num.'件',
'goods_name' => omit_str(($order->order_goods[0]['goods_name'] ?? '商品'), 8)
]
]);
$order_contact_mobile = ConfigServer::get('order_message', 'order_contact_mobile');
//平台短信通知
if($order_contact_mobile) {
Hook::listen('sms_send',[
'key' => NoticeSetting::USER_PAID_NOTICE_PLATFORM,
'mobile' => $order_contact_mobile,
'params' => [
'order_sn' => $order['order_sn'],
],
]);
}
// 赠送成长值和积分
Hook::listen('give_reward', [
'order_id' => $order['id'],
'scene' => 1, //1=下单支付场景
]);
// 钩子-记录足迹(下单结算)
Hook::listen('footprint', [
'type' => Footprint::place_order,
'user_id' => $user['id'],
'foreign_id' => $order['id'], //订单ID
'total_money' => $order['order_amount'] //订单应付金额
]);
//打印订单
Hook::listen('printer', [
'order_id' => $order['id'],
]);
}
/**
* note 充值回调
* create_time 2020/10/26 18:53
*/
private static function recharge($order_sn,$extra = []){
$new = time();
$order = Db::name('recharge_order')->where(['order_sn'=>$order_sn])->find();
$update_data['pay_time'] = $new;
$update_data['pay_status'] = Pay::ISPAID;
if (isset($extra['transaction_id'])) {
$update_data['transaction_id'] = $extra['transaction_id'];
}
Db::name('recharge_order')->where(['id'=>$order['id']])->update($update_data);
$user = User::get($order['user_id']);
$total_money = $order['order_amount']+$order['give_money'];
$total_integral = $order['give_integral'];
$user->user_money = ['inc', $total_money];
$user->user_integral = ['inc', $total_integral];
$user->user_growth = ['inc', $order['give_growth']];
$user->total_recharge_amount = ['inc',$total_money];
$user->save();
//记录余额
$total_money > 0 && AccountLogLogic::AccountRecord($user->id,$total_money,1, AccountLog::recharge_money);
//记录积分
$total_integral > 0 && AccountLogLogic::AccountRecord($user->id,$total_integral,1, AccountLog::recharge_give_integral);
//记录成长值
$order['give_growth'] > 0 &&AccountLogLogic::AccountRecord($user->id,$order['give_growth'],1, AccountLog::recharge_give_growth);
}
}
@@ -0,0 +1,203 @@
<?php
// +----------------------------------------------------------------------
// | likeshop开源商城系统
// +----------------------------------------------------------------------
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
// | gitee下载:https://gitee.com/likeshop_gitee
// | github下载:https://github.com/likeshop-github
// | 访问官网:https://www.likeshop.cn
// | 访问社区:https://home.likeshop.cn
// | 访问手册:http://doc.likeshop.cn
// | 微信公众号:likeshop技术社区
// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
// | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
// | 禁止对系统程序代码以任何目的,任何形式的再发布
// | likeshop团队版权所有并拥有最终解释权
// +----------------------------------------------------------------------
// | author: likeshop.cn.team
// +----------------------------------------------------------------------
namespace app\common\logic;
use app\common\server\AliPayServer;
use app\common\server\BalancePayServer;
use app\common\server\WeChatPayServer;
use app\common\model\{Client_, Order, Pay, User};
use think\facade\Env;
use think\Db;
class PaymentLogic extends LogicBase
{
public static $error = '';
public static $return_code = 0;
/**
* Notes: 错误信息
* @return string
* @author 段誉(2021/2/1 11:19)
*/
public static function getError()
{
return self::$error;
}
/**
* Notes: 返回状态码
* @return int
* @author 段誉(2021/2/1 11:19)
*/
public static function getReturnCode()
{
return self::$return_code;
}
/**
* Notes: 支付
* @param $from
* @param $order
* @param $order_source
* @return array|bool|string
* @author 段誉(2021/2/1 11:19)
*/
public static function pay($from, $order, $order_source)
{
// 更新订单支付方式
if($from == 'order') {
Order::update([
'id' => $order['id'],
'pay_way' => $order['pay_way']
]);
}
if($from == 'recharge') {
Db::name('recharge_order')->where('id', $order['id'])->update(['pay_way' => $order['pay_way']]);
}
// 订单金额为0的情况,直接走支付回调接口
if($order['order_amount'] == 0) {
PayNotifyLogic::handle('order', $order['order_sn'], []);
return $order['id'];
}
switch ($order['pay_way']) {
case Pay::WECHAT_PAY:
$res = WeChatPayServer::unifiedOrder($from, $order, $order_source);
if (false === $res) {
self::$error = WeChatPayServer::getError();
}
break;
case Pay::ALI_PAY:
$aliPay = new AliPayServer();
$res = $aliPay->pay($from, $order, $order_source);
if(false === $res) {
self::$error = $aliPay->getError();
} else {
self::$return_code = 10001;//特殊状态码,用于前端判断
}
break;
case Pay::BALANCE_PAY:
$balancePay = new BalancePayServer();
$res = $balancePay->pay($from, $order, $order_source);
if($res !== false) {
PayNotifyLogic::handle('order', $order['order_sn'], []);
self::$return_code = 20001;//特殊状态码,用于前端判断
}else{
self::$error = $balancePay->getError();
}
break;
default:
self::$error = '订单异常';
$res = false;
}
return $res;
}
/**
* Notes: pc预支付
* @param $order
* @author 段誉(2021/3/17 14:56)
* @return array|bool|string
* @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
* @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
* @throws \GuzzleHttp\Exception\GuzzleException
*/
public static function pcPay($order, $order_source = Client_::pc)
{
$res = [];
// 更新订单支付方式
Order::update([
'id' => $order['id'],
'pay_way' => $order['pay_way']
]);
// 订单金额为0的情况,直接走支付回调接口
if($order['order_amount'] == 0) {
PayNotifyLogic::handle('order', $order['order_sn'], []);
self::$return_code = 10001;//特殊状态码,用于前端判断
return $order['id'];
}
switch ($order['pay_way']) {
case Pay::WECHAT_PAY:
$res = WeChatPayServer::unifiedOrder('order', $order, $order_source);
if (false === $res) {
self::$error = WeChatPayServer::getError();
return false;
}
break;
case Pay::BALANCE_PAY:
$user = User::get($order['user_id']);
if ($user['user_money'] < $order['order_amount']) {
self::$error = '余额不足';
return false;
}
$balancePay = new BalancePayServer();
$res = $balancePay->pay('order', $order, '5');
if($res !== false) {
PayNotifyLogic::handle('order', $order['order_sn'], []);
self::$return_code = 10001;//特殊状态码,用于前端判断
}else{
self::$error = $balancePay->getError();
return false;
}
break;
case Pay::ALI_PAY:
if ($order_source != Client_::pc) {
self::$error = '支付类型错误';
return false;
}
$aliPay = new AliPayServer();
$res = $aliPay->pay('order', $order, $order_source);
if (false === $res) {
self::$error = $aliPay->getError();
return false;
}
self::$return_code = 20001;//特殊状态码,用于前端判断
break;
default:
self::$error = '无效的支付方式';
return false;
}
return $res;
}
/**
* Notes: 是否在白名单内支付
* @param $user_id
* @author 段誉(2021/2/24 10:01)
* @return bool
*/
public static function isPayWhiteList($user_id)
{
$white_list = Env::get('wechat.white_list', '');
$white_list = explode(',', $white_list);
if (in_array($user_id, $white_list)) {
return true;
}
return false;
}
}
@@ -0,0 +1,594 @@
<?php
// +----------------------------------------------------------------------
// | likeshop开源商城系统
// +----------------------------------------------------------------------
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
// | gitee下载:https://gitee.com/likeshop_gitee
// | github下载:https://github.com/likeshop-github
// | 访问官网:https://www.likeshop.cn
// | 访问社区:https://home.likeshop.cn
// | 访问手册:http://doc.likeshop.cn
// | 微信公众号:likeshop技术社区
// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
// | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
// | 禁止对系统程序代码以任何目的,任何形式的再发布
// | likeshop团队版权所有并拥有最终解释权
// +----------------------------------------------------------------------
// | author: likeshop.cn.team
// +----------------------------------------------------------------------
namespace app\common\logic;
use app\common\server\ConfigServer;
use app\common\server\storage\Driver as StorageDriver;
use app\common\server\UrlServer;
use app\common\server\WeChatServer;
use Endroid\QrCode\QrCode;
use think\facade\Cache;
use think\Exception;
use EasyWeChat\Factory;
class QrCodeLogic extends LogicBase{
//商品图片配置
public function goodsShareConfig(){
return [
//会员头像
'head_pic' => [
'w' => 64, 'h' => 64, 'x' => 40, 'y' => 20,
],
//会员昵称
'nickname' => [
'color' => '#555555', 'font_face' => ROOT_PATH .'/font/SourceHanSansCN-Regular.otf', 'font_size' => 19, 'x' => 120, 'y' => 60,
],
//标题
'title' => [
'color' => '#333333', 'font_face' => ROOT_PATH .'/font/SourceHanSansCN-Bold.otf', 'font_size' => 20, 'w' => 360, 'x' => 40, 'y' => 785,
],
//价格符号
'price_symbol' => [
'color' => '#FF2C3C', 'font_face' => ROOT_PATH .'/font/SourceHanSansCN-Regular.otf', 'font_size' => 22, 'w' => 140, 'x' => 40, 'y' => 722,
],
//商品价格
'price' => [
'color' => '#FF2C3C', 'font_face' => ROOT_PATH .'/font/SourceHanSansCN-Bold.otf', 'font_size' => 32, 'w' => 140, 'x' => 64, 'y' => 722,
],
//小数
'decimal'=> [
'color' => '#FF2C3C', 'font_face' => ROOT_PATH .'/font/SourceHanSansCN-Bold.otf', 'font_size' => 22, 'w' => 140, 'x' => 114, 'y' => 722,
],
//市场价
'market_price_symbol' => [
'color' => '#999999', 'font_face' => ROOT_PATH .'/font/SourceHanSansCN-Regular.otf', 'font_size' => 22, 'w' => 140, 'x' => 142, 'y' => 722,
],
//市场价符号
'market_price' => [
'color' => '#999999', 'font_face' => ROOT_PATH .'/font/SourceHanSansCN-Regular.otf', 'font_size' => 20, 'w' => 140, 'x' => 168, 'y' => 722,
],
//推广主图商品主图
'main_pic' => [
'w' => 560, 'h' => 560, 'x' => 40, 'y' => 100,
],
//提醒长按扫码
'notice' => [
'color' => '#888888', 'font_face' => ROOT_PATH .'/font/SourceHanSansCN-Regular.otf', 'font_size' => 18, 'x' => 432, 'y' => 895,
],
//二维码
'qr' => [
'w' => 165,'h' => 165, 'x' => 436, 'y' => 700,
],
];
}
//生成商品分享图
public function makeGoodsPoster($user,$goods,$url,$url_type){
try {
$save_dir = ROOT_PATH .'/uploads/qr_code/goods_share/';
$background_img = ROOT_PATH .'/images/share/share_goods_bg.png';
!file_exists($save_dir) && mkdir($save_dir, 0777, true);
$cache_key = 'gid' . $goods['id'].'uid'.$user['id'].$url_type;
$qr_src = md5($cache_key) . '.png';
$poster_url = $save_dir . $qr_src;
$base64 = Cache::get($cache_key);
if (!empty($base64)) {
return self::dataSuccess('海报生成成功',$base64);
}
$poster_config = self::goodsShareConfig();
//生成二维码
if($url_type == 'path'){
$scene = 'id='.$goods['id'].'&invite_code='.$user['distribution_code'];
$result = $this->makeMnpQrcode($scene,$url,$qr_src,$save_dir);
if(true !== $result){
return self::dataError('微信配置错误:'.$result);
}
}else{
$qrCode = new QrCode();
$qrCode->setText($url);
$qrCode->setSize(1000);
$qrCode->setWriterByName('png');
$qrCode->writeFile($poster_url);
}
$user_avatar = UrlServer::getFileUrl($user['avatar'],'share');
//判断头像是否存在
if(!check_file_exists($user_avatar)){
//如果不存在,使用默认头像
$user_avatar = ROOT_PATH.ConfigServer::get('website', 'user_image');
}
//默认商品主图
$goods_image = UrlServer::getFileUrl($goods['image'],'share');
//判断是否有自定义分享海报图
if($goods['poster']){
$goods_image = UrlServer::getFileUrl($goods['poster'],'share');
}
if(!check_file_exists($goods_image)){
//如果不存在,使用默认商品主图
$goods_image = ROOT_PATH.ConfigServer::get('website', 'goods_image');
}
$qr_code_logic = new QrCodeLogic();
//获取背景图
$share_background_img = imagecreatefromstring(file_get_contents($background_img));
//合成头像
$qr_code_logic->writeImg($share_background_img, $user_avatar, $poster_config['head_pic'],true);
//合并商品主图
$qr_code_logic->writeImg($share_background_img, $goods_image, $poster_config['main_pic'],false);
//合成昵称
$nickname = filterEmoji($user['nickname']);
$nickname = '来自'.$nickname.'的分享';
$qr_code_logic->writeText($share_background_img, $nickname, $poster_config['nickname']);
//长按识别
$notice = '长按识别二维码';
$qr_code_logic->writeText($share_background_img, $notice, $poster_config['notice']);
//合成价格
$qr_code_logic->writeText($share_background_img, '¥', $poster_config['price_symbol']);
$qr_code_logic->writeText($share_background_img, floatval($goods['min_price']), $poster_config['price']);
//合成商品标题
$goods_name = auto_adapt($poster_config['title']['font_size'], 0, $poster_config['title']['font_face'], $goods['name'], $poster_config['title']['w'],$poster_config['title']['y'],getimagesize($background_img));
$qr_code_logic->writeText($share_background_img, $goods_name, $poster_config['title']);
//合成二维码
$qr_code_logic->writeImg($share_background_img, $poster_url, $poster_config['qr'],false);
imagepng($share_background_img, $poster_url);
if ($fp = fopen($poster_url, "rb", 0)) {
$gambar = fread($fp, filesize($poster_url));
fclose($fp);
$base64 = chunk_split(base64_encode($gambar));
$base64 = 'data:image/png;base64,' . $base64;
}
//删除文件
if (strstr($poster_url, $save_dir)) {
unlink($poster_url);
}
Cache::set($cache_key, $base64, 3600);
return self::dataSuccess('海报生成成功',$base64);
}catch (Exception $e){
return self::dataError('海报生成错误:' . $e->getMessage());
}
}
//用户图片配置
public function userShareConfig()
{
return [
//会员头像
'head_pic' => [
'w' => 80, 'h' => 80, 'x' => 30, 'y' => 680,
],
//会员昵称
'nickname' => [
'color' => '#333333', 'font_face' => ROOT_PATH.'/font/SourceHanSansCN-Regular.otf', 'font_size' => 20, 'x' => 120, 'y' => 730,
],
//标题
'title' => [
'color' => '#333333', 'font_face' => ROOT_PATH.'/font/SourceHanSansCN-Regular.otf', 'font_size' => 20, 'w' => 360, 'x' => 30, 'y' => 810,
],
//提醒长按扫码
'notice' => [
'color' => '#333333', 'font_face' => ROOT_PATH.'/font/SourceHanSansCN-Regular.otf', 'font_size' => 20, 'x' => 30, 'y' => 880,
],
//邀请码文本
'code_text' => [
'color' => '#FF2C3C', 'font_face' => ROOT_PATH.'/font/SourceHanSansCN-Regular.otf', 'font_size' => 20, 'x' => 355, 'y' => 930,
],
//二维码
'qr' => [
'w' => 170,'h' => 170, 'x' => 370, 'y' => 730,
],
];
}
//生成用户小程序二维码
public function makeUserMnpQrcode($code,$content,$img_src)
{
try {
$config = WeChatServer::getMnpConfig();
$app = Factory::miniProgram($config);
$response = $app->app_code->get($content.'?invite_code='.$code, [
'width' => 170,
]);
if ($response instanceof \EasyWeChat\Kernel\Http\StreamResponse) {
$response->saveAs('uploads/qr_code/user_share/', $img_src);
return true;
}
if(isset($response['errcode']) && 41030 === $response['errcode']){
return '商城小程序码,先提交审核并通过';
}
return $response['errmsg'];
} catch (\EasyWeChat\Kernel\Exceptions\Exception $e){
return $e->getMessage();
}
}
//获取分享海报背景
public function getSharePosterBg()
{
$share_bg = ConfigServer::get('invite', 'poster');
// 获取存储引擎
$config = [
'default' => ConfigServer::get('storage', 'default', 'local'),
'engine' => ConfigServer::get('storage_engine')
];
if ($config['default'] == 'local') {
return ROOT_PATH .'/'.$share_bg;
} else {
$share_bg = UrlServer::getFileUrl($share_bg,'share');
if (!check_file_exists($share_bg)) {
return ROOT_PATH .'/images/share/share_user_bg.png';
}
return $share_bg;
}
}
//删除旧的文件
public function delOldPoster($poster_url, $save_dir, $qr_src)
{
// 获取存储引擎
$config = [
'default' => ConfigServer::get('storage', 'default', 'local'),
'engine' => ConfigServer::get('storage_engine')
];
if ($config['default'] == 'local') {
//删除文件
if (file_exists($poster_url) && strstr($poster_url, $save_dir)) {
unlink($poster_url);
}
} else {
try{
$StorageDriver = new StorageDriver($config);
$file_name = $save_dir . $qr_src;
$StorageDriver->delete($file_name);
} catch(Exception $e) {
}
}
}
//生成用户分享图
public function makeUserPoster($user, $content, $url_type, $client)
{
try {
$save_dir = 'uploads/qr_code/user_share/';
$background_img = $this->getSharePosterBg();
!file_exists($save_dir) && mkdir($save_dir, 0777, true);
$save_key = 'uid'.$user['id'].$url_type.$client;
$qr_src = md5($save_key) . '.png';
$poster_url = ROOT_PATH.'/'.$save_dir . $qr_src;
//删除旧的图片
$this->delOldPoster($poster_url, $save_dir, $qr_src);
$poster_config = $this->userShareConfig();
//生成二维码
if($url_type == 'path'){
$result = $this->makeUserMnpQrcode($user['distribution_code'], $content, $qr_src);
if(true !== $result){
return ['status' => 0, 'msg' => '微信配置错误:'.$result, 'data' => ''];
}
}else{
$qrCode = new QrCode();
$qrCode->setText($content);
$qrCode->setSize(1000);
$qrCode->setWriterByName('png');
$qrCode->writeFile($poster_url);
}
$user_avatar = UrlServer::getFileUrl($user['avatar'],'share');
//判断头像是否存在
if(!check_file_exists($user_avatar)){
//如果不存在,使用默认头像
$user_avatar = ROOT_PATH.ConfigServer::get('website', 'user_image');
}
$qr_code_logic = new QrCodeLogic();
//获取背景图
$share_background_img = imagecreatefromstring(file_get_contents($background_img));
//合成头像
$qr_code_logic->writeImg($share_background_img, $user_avatar, $poster_config['head_pic'],true);
//合成昵称
$nickname = filterEmoji($user['nickname']);
$qr_code_logic->writeText($share_background_img, $nickname, $poster_config['nickname']);
//长按识别
$notice = '长按识别二维码 >>';
$qr_code_logic->writeText($share_background_img, $notice, $poster_config['notice']);
//合成商品标题
$title = auto_adapt($poster_config['title']['font_size'], 0, $poster_config['title']['font_face'], '邀请你一起来赚大钱', $poster_config['title']['w'],$poster_config['title']['y'],getimagesize($background_img));
$qr_code_logic->writeText($share_background_img, $title, $poster_config['title']);
//邀请码
$qr_code_logic->writeText($share_background_img, '邀请码 '.$user['distribution_code'], $poster_config['code_text']);
//合成二维码
$qr_code_logic->writeImg($share_background_img, $poster_url, $poster_config['qr'],false);
imagepng($share_background_img, $poster_url);
$file_name = $save_dir . $qr_src;
$local_uir = ROOT_PATH.'/'.$file_name;
self::upload($local_uir, $file_name);
return ['status' => 1, 'msg' => '', 'data' => $file_name.'?v='.time()];
}catch (Exception $e){
return ['status' => 0, 'msg' => $e->getMessage(), 'data' => ''];
}
}
/**
* Notes: 生成的图片根据不同的存储方式储存
* @param $local_uri 本地图片路径
* @param $img_uri 图片地址名称
* @author 段誉(2021/3/2 18:47)
* @throws Exception
*/
public function upload($local_uri, $file_name)
{
$config = [
'default' => ConfigServer::get('storage', 'default', 'local'),
'engine' => ConfigServer::get('storage_engine')
];
if (empty($config['engine']['local'])) {
$config['engine']['local'] = [];
}
if ($config['default'] != 'local') {
$StorageDriver = new StorageDriver($config);
if (!$StorageDriver->fetch($local_uri, $file_name)) {
throw new Exception('图片保存出错:' . $StorageDriver->getError());
}
//删除本地图片
@unlink($file_name);
}
}
//砍价图片配置
public function bargainShareConfig(){
return [
//会员头像
'head_pic' => [
'w' => 64, 'h' => 64, 'x' => 40, 'y' => 20,
],
//会员昵称
'nickname' => [
'color' => '#555555', 'font_face' => ROOT_PATH .'/font/SourceHanSansCN-Regular.otf', 'font_size' => 19, 'x' => 120, 'y' => 60,
],
'bargain_title' => [
'color' => '#FF2C3C', 'font_face' => ROOT_PATH .'/font/SourceHanSansCN-Bold.otf', 'font_size' => 24, 'w' => 360, 'x' => 40, 'y' => 735,
],
'brief_title' => [
'color' => '#F95F2F', 'font_face' => ROOT_PATH .'/font/SourceHanSansCN-Regular.otf', 'font_size' => 16, 'w' => 360, 'x' => 40, 'y' => 765,
],
//标题
'title' => [
'color' => '#333333', 'font_face' => ROOT_PATH .'/font/SourceHanSansCN-Regular.otf', 'font_size' => 20, 'w' => 360, 'x' => 40, 'y' => 795,
],
//推广主图商品主图
'main_pic' => [
'w' => 560, 'h' => 560, 'x' => 40, 'y' => 100,
],
//提醒长按扫码
'notice' => [
'color' => '#888888', 'font_face' => ROOT_PATH .'/font/SourceHanSansCN-Regular.otf', 'font_size' => 18, 'x' => 432, 'y' => 895,
],
//二维码
'qr' => [
'w' => 165,'h' => 165, 'x' => 436, 'y' => 700,
],
];
}
public function makeBargainPoster($user,$bargain_launch,$url,$url_type){
try {
$save_dir = ROOT_PATH .'/uploads/qr_code/bargain_share/';
$background_img = ROOT_PATH .'/images/share/share_goods_bg.png';
!file_exists($save_dir) && mkdir($save_dir,0777,true);
$cache_key = 'bid' . $bargain_launch['id'].'uid'.$user['id'].$url_type;
$qr_src = md5($cache_key) . '.png';
$poster_url = $save_dir . $qr_src;
$base64 = Cache::get($cache_key);
if (!empty($base64)) {
return self::dataSuccess('海报生成成功',$base64);
}
$poster_config = self::bargainShareConfig();
//生成二维码
if($url_type == 'path'){
$scene = 'id='.$bargain_launch['id'];
$result = $this->makeMnpQrcode($scene,$url,$qr_src,$save_dir);
if(true !== $result){
return self::dataError('微信配置错误:'.$result);
}
}else{
$qrCode = new QrCode();
$qrCode->setText($url);
$qrCode->setSize(1000);
$qrCode->setWriterByName('png');
$qrCode->writeFile($poster_url);
}
$user_avatar = UrlServer::getFileUrl($user['avatar'],'share');
//判断头像是否存在
if(!check_file_exists($user_avatar)){
//如果不存在,使用默认头像
$user_avatar = ROOT_PATH.ConfigServer::get('website', 'user_image');
}
//判断商品主图是否存在
$goods_image = UrlServer::getFileUrl($bargain_launch['goods_snap']['goods_iamge'],'share');
if(!check_file_exists($goods_image)){
//如果不存在,使用默认商品主图
$goods_image = ROOT_PATH.ConfigServer::get('website', 'goods_image');
}
$qr_code_logic = new QrCodeLogic();
//获取背景图
$share_background_img = imagecreatefromstring(file_get_contents($background_img));
//合成头像
$qr_code_logic->writeImg($share_background_img, $user_avatar, $poster_config['head_pic'],true);
//合并商品主图
$qr_code_logic->writeImg($share_background_img, $goods_image, $poster_config['main_pic'],false);
//合成昵称
$nickname = filterEmoji($user['nickname']);
$nickname = '来自'.$nickname.'的分享';
$qr_code_logic->writeText($share_background_img, $nickname, $poster_config['nickname']);
//长按识别
$notice = '长按识别二维码';
$qr_code_logic->writeText($share_background_img, $notice, $poster_config['notice']);
//合成砍价标题
$bargain_title = '我正在参与砍价 还差一步';
$qr_code_logic->writeText($share_background_img, $bargain_title, $poster_config['bargain_title']);
//合成简介
$brief_title = '帮忙砍一刀';
$qr_code_logic->writeText($share_background_img, $brief_title, $poster_config['brief_title']);
//合成商品标题
$goods_name = auto_adapt($poster_config['title']['font_size'], 0, $poster_config['title']['font_face'], $bargain_launch['goods_snap']['name'], $poster_config['title']['w'],$poster_config['title']['y'],getimagesize($background_img));
$qr_code_logic->writeText($share_background_img, $goods_name, $poster_config['title']);
//合成二维码
$qr_code_logic->writeImg($share_background_img, $poster_url, $poster_config['qr'],false);
imagepng($share_background_img, $poster_url);
if ($fp = fopen($poster_url, "rb", 0)) {
$gambar = fread($fp, filesize($poster_url));
fclose($fp);
$base64 = chunk_split(base64_encode($gambar));
$base64 = 'data:image/png;base64,' . $base64;
}
//删除文件
if (strstr($poster_url, $save_dir)) {
unlink($poster_url);
}
$expire = $bargain_launch['launch_end_time'] - time();
Cache::set($cache_key, $base64, $expire);
return self::dataSuccess('海报生成成功',$base64);
}catch (Exception $e){
return self::dataError('海报生成错误:' . $e->getMessage());
}
}
//小程序生成二维码(非永久码)
public function makeMnpQrcode($scene,$url,$img_src,$save_dir){
try {
$config = WeChatServer::getMnpConfig();
$app = Factory::miniProgram($config);
$response = $app->app_code->getUnlimit($scene, [
'page' => $url,
]);
if ($response instanceof \EasyWeChat\Kernel\Http\StreamResponse) {
$response->saveAs($save_dir, $img_src);
return true;
}
if(isset($response['errcode']) && 41030 === $response['errcode']){
return '商城小程序未上线或商城小程序页面发布';
}
return $response['errmsg'];
} catch (\EasyWeChat\Kernel\Exceptions\Exception $e){
return $e->getMessage();
}
}
//写入图片
public function writeImg($poster, $img_uri, $config, $is_rounded = false){
$pic_img = imagecreatefromstring(file_get_contents($img_uri));
$is_rounded?$pic_img = rounded_corner($pic_img):'';//切成圆角返回头像资源
$pic_w = imagesx($pic_img);
$pic_h = imagesy($pic_img);
//圆形头像大图合并到海报
imagecopyresampled($poster, $pic_img,
$config['x'],
$config['y'],
0, 0,
$config['w'],
$config['h'],
$pic_w,
$pic_h
);
return $poster;
}
//写入文字
public function writeText($poster, $text, $config){
$font_uri = $config['font_face'];
$font_size = $config['font_size'];
$color = substr($config['color'],1);
//颜色转换
$color= str_split($color, 2);
$color = array_map('hexdec', $color);
if (empty($color[3]) || $color[3] > 127) {
$color[3] = 0;
}
//写入文字
$font_col = imagecolorallocatealpha($poster, $color[0], $color[1], $color[2], $color[3]);
imagettftext($poster, $font_size,0, $config['x'], $config['y'], $font_col, $font_uri, $text);
return $poster;
}
}
@@ -0,0 +1,75 @@
<?php
// +----------------------------------------------------------------------
// | likeshop开源商城系统
// +----------------------------------------------------------------------
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
// | gitee下载:https://gitee.com/likeshop_gitee
// | github下载:https://github.com/likeshop-github
// | 访问官网:https://www.likeshop.cn
// | 访问社区:https://home.likeshop.cn
// | 访问手册:http://doc.likeshop.cn
// | 微信公众号:likeshop技术社区
// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
// | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
// | 禁止对系统程序代码以任何目的,任何形式的再发布
// | likeshop团队版权所有并拥有最终解释权
// +----------------------------------------------------------------------
// | author: likeshop.cn.team
// +----------------------------------------------------------------------
namespace app\common\logic;
use app\common\model\NoticeSetting;
use app\common\model\SmsLog;
class SmsLogic
{
protected $message_key = '';
protected $mobile = '';
protected $code = '';
protected $sms = '';
protected $indate = 300;//todo 验证码有效期
public function __construct($key, $mobile, $code)
{
$this->message_key = NoticeSetting::SMS_SCENE[$key];
$this->mobile = $mobile;
$this->code = $code;
$sms_Log = new SmsLog();
$sms = $sms_Log
->where(['message_key' => $this->message_key, 'mobile' => $this->mobile, 'is_verify' => 0])
->order('id desc')
->field('id,code,send_time')
->find();
$this->sms = $sms;
}
//检查验证码
public function checkCode()
{
if (!isset($this->sms) || $this->sms->code !== $this->code) {
return '验证码错误';
}
$send_time = $this->sms->getData('send_time');
$now = time();
if ($this->sms->code === $this->code && $send_time + $this->indate < $now) {
return '验证码已过期';
}
return true;
}
//标记已验证
public function cancelCode()
{
if (empty($this->sms)) {
return false;
}
unset($this->sms->send_time);
$this->sms->is_verify = 1;
$this->sms->update_time = time();
return $this->sms->save();
}
}
@@ -0,0 +1,64 @@
<?php
// +----------------------------------------------------------------------
// | likeshop开源商城系统
// +----------------------------------------------------------------------
// | 欢迎阅读学习系统程序代码,建议反馈是我们前进的动力
// | gitee下载:https://gitee.com/likeshop_gitee
// | github下载:https://github.com/likeshop-github
// | 访问官网:https://www.likeshop.cn
// | 访问社区:https://home.likeshop.cn
// | 访问手册:http://doc.likeshop.cn
// | 微信公众号:likeshop技术社区
// | likeshop系列产品在gitee、github等公开渠道开源版本可免费商用,未经许可不能去除前后端官方版权标识
// | likeshop系列产品收费版本务必购买商业授权,购买去版权授权后,方可去除前后端官方版权标识
// | 禁止对系统程序代码以任何目的,任何形式的再发布
// | likeshop团队版权所有并拥有最终解释权
// +----------------------------------------------------------------------
// | author: likeshop.cn.team
// +----------------------------------------------------------------------
namespace app\common\logic;
use think\Db;
class UserLevelLogic{
/**
* note 用户升级 更新个人会员等级
* create_time 2020/11/26 18:52
*/
public static function updateUserLevel($id){
$user = Db::name('user')->where(['id'=>$id])->field('user_growth,level')->find();
$level = Db::name('user_level')
->where([['growth_value','<=',$user['user_growth']],['del','=',0]])
->order('growth_value desc')
->find();
if($level){
$growth_value = 0;
$user['level'] > 0 && $growth_value = Db::name('user_level')->where(['id'=>$user['level']])->value('growth_value');
if($level['growth_value'] > $growth_value){
Db::name('user')->where(['id'=>$id])->update(['level'=>$level['id'],'update_time'=>time()]);
}
}
return true;
}
/**
* note 用户升级 更新所有用户的等级
* create_time 2020/11/26 19:11
*/
public static function updateAllUserLevel($level_id){
$growth_value = Db::name('user_level')->where(['id'=>$level_id])->value('growth_value');
$no_update_user_ids = Db::name('user')->alias('U')
->join('user_level L','U.level = L.id')
->where('L.growth_value','>',$growth_value)
->column('U.id');
return Db::name('user')
->where([
['id','not in',$no_update_user_ids],
['del','=',0],
['user_growth','>=',$growth_value],
])->update(['level'=>$level_id,'update_time'=>time()]);
}
}