商品Address

This commit is contained in:
2025-01-16 11:34:04 +08:00
parent 98a5c4f73f
commit c59d865fd8
33 changed files with 3179 additions and 3 deletions

View File

@ -2,7 +2,15 @@
namespace plugin\points_mall\controller;
use HttpResponseException;
use plugin\points_mall\model\PointsMallGoodsStock;
use plugin\points_mall\model\PointsMallGoods;
use plugin\points_mall\model\PointsMallGoodsCate;
use plugin\points_mall\model\PointsMallGoodsItem;
use plugin\points_mall\service\GoodsService;
use think\admin\Controller;
use think\admin\extend\CodeExtend;
use think\admin\helper\QueryHelper;
/**
* 商品管理
@ -10,13 +18,211 @@ use think\admin\Controller;
class Goods extends Controller
{
/**
* 商品管理
* 商品数据管理
* @auth true
* @menu true
* @return void
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$this->title = '商品管理';
$this->type = $this->request->get('type', 'index');
PointsMallGoods::mQuery($this->get)->layTable(function () {
$this->title = '商品数据管理';
$this->cates = PointsMallGoodsCate::items();
}, function (QueryHelper $query) {
$query->withoutField('specs,content')->like('code|name#name')->like('marks,cates', ',');
$query->equal('status,level_upgrade,delivery_code,rebate_type')->dateBetween('create_time');
$query->where(['status' => intval($this->type === 'index'), 'deleted' => 0]);
});
}
/**
* 商品选择器
* @login true
* @return void
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function select()
{
$this->get['status'] = 1;
$this->get['deleted'] = 0;
$this->index();
}
/**
* 添加商品数据
* @auth true
*/
public function add()
{
$this->mode = 'add';
$this->title = '添加商品数据';
PointsMallGoods::mForm('form', 'code');
}
/**
* 编辑商品数据
* @auth true
*/
public function edit()
{
$this->mode = 'edit';
$this->title = '编辑商品数据';
PointsMallGoods::mForm('form', 'code');
}
/**
* 复制编辑商品
* @auth true
*/
public function copy()
{
$this->mode = 'copy';
$this->title = '复制编辑商品';
PointsMallGoods::mForm('form', 'code');
}
/**
* 表单数据处理
* @param array $data
*/
protected function _copy_form_filter(array &$data)
{
if ($this->request->isPost()) {
$data['code'] = CodeExtend::uniqidNumber(16, 'G');
}
}
/**
* 表单数据处理
* @param array $data
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
protected function _form_filter(array &$data)
{
if (empty($data['code'])) {
$data['code'] = CodeExtend::uniqidNumber(16, 'G');
}
if ($this->request->isGet()) {
$this->cates = PointsMallGoodsCate::items(true);
$data['marks'] = $data['marks'] ?? [];
$data['cates'] = $data['cates'] ?? [];
$data['specs'] = json_encode($data['specs'] ?? [], 64 | 256);
$data['items'] = PointsMallGoodsItem::itemsJson($data['code']);
$data['slider'] = is_array($data['slider'] ?? []) ? join('|', $data['slider'] ?? []) : '';
$data['delivery_code'] = $data['delivery_code'] ?? 'FREE';
} elseif ($this->request->isPost()) try {
if (empty($data['cover'])) $this->error('商品图片不能为空!');
if (empty($data['slider'])) $this->error('轮播图片不能为空!');
// 商品规格保存
[$count, $items] = [0, json_decode($data['items'], true)];
$data['marks'] = arr2str($data['marks'] ?? []);
foreach ($items as $item) if ($item['status'] > 0) {
$count++;
$data['price_market'] = min($data['price_market'] ?? $item['market'], $item['market']);
$data['price_selling'] = min($data['price_selling'] ?? $item['selling'], $item['selling']);
$data['allow_balance'] = max($data['allow_balance'] ?? $item['allow_balance'], $item['allow_balance']);
$data['allow_integral'] = max($data['allow_integral'] ?? $item['allow_integral'], $item['allow_integral']);
}
if (empty($count)) $this->error('无效的的商品价格信息!');
$this->app->db->transaction(static function () use ($data, $items) {
// 标识所有规格无效
PointsMallGoodsItem::mk()->where(['gcode' => $data['code']])->update(['status' => 0]);
$model = PointsMallGoods::mk()->where(['code' => $data['code']])->findOrEmpty();
$model->{$model->isExists() ? 'onAdminUpdate' : 'onAdminInsert'}($data['code']);
$model->save($data);
// 更新或写入商品规格
foreach ($items as $item) PointsMallGoodsItem::mUpdate([
'gsku' => $item['gsku'],
'ghash' => $item['hash'],
'gcode' => $data['code'],
'gspec' => $item['spec'],
'gimage' => $item['image'],
'status' => $item['status'] ? 1 : 0,
'price_cost' => $item['cost'],
'price_market' => $item['market'],
'price_selling' => $item['selling'],
'allow_balance' => $item['allow_balance'],
'allow_integral' => $item['allow_integral'],
'number_virtual' => $item['virtual'],
'number_express' => $item['express'],
'reward_balance' => $item['balance'],
'reward_integral' => $item['integral'],
], 'ghash', ['gcode' => $data['code']]);
});
// 刷新产品库存
GoodsService::stock($data['code']);
$this->success('商品编辑成功!', 'javascript:history.back()');
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
throw $exception;
// $this->error($exception->getMessage());
}
}
/**
* 商品库存入库
* @auth true
* @return void
*/
public function stock()
{
$input = $this->_vali(['code.require' => '商品不能为空哦!']);
if ($this->request->isGet()) {
$this->vo = PointsMallGoods::mk()->where($input)->with('items')->findOrEmpty()->toArray();
empty($this->vo) ? $this->error('无效的商品!') : $this->fetch();
} else try {
[$data, $post, $batch] = [[], $this->request->post(), CodeExtend::uniqidDate(12, 'B')];
if (isset($post['gcode']) && is_array($post['gcode'])) {
foreach (array_keys($post['gcode']) as $key) if ($post['gstock'][$key] > 0) $data[] = [
'batch_no' => $batch,
'ghash' => $post['ghash'][$key],
'gcode' => $post['gcode'][$key],
'gspec' => $post['gspec'][$key],
'gstock' => $post['gstock'][$key],
];
empty($data) || PointsMallGoodsStock::mk()->saveAll($data);
}
GoodsService::stock($input['code']);
$this->success('库存更新成功!');
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $e) {
throw $e;
// $this->error($e->getMessage());
}
}
/**
* 商品上下架
* @auth true
*/
public function state()
{
PointsMallGoods::mSave($this->_vali([
'status.in:0,1' => '状态值范围异常!',
'status.require' => '状态值不能为空!',
]), 'code');
}
/**
* 删除商品数据
* @auth true
*/
public function remove()
{
PointsMallGoods::mSave($this->_vali([
'code.require' => '编号不能为空!',
'deleted.value' => 1
]), 'code');
}
}

View File

@ -0,0 +1,114 @@
<?php
namespace plugin\points_mall\controller;
use plugin\points_mall\model\PointsMallGoodsCate;
use think\admin\Controller;
use think\admin\extend\DataExtend;
use think\admin\helper\QueryHelper;
class GoodsCate extends Controller
{
/**
* 最大级别
* @var integer
*/
protected $maxLevel = 3;
/**
* 商品分类管理
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
PointsMallGoodsCate::mQuery($this->get)->layTable(function () {
$this->title = "商品分类管理";
}, static function (QueryHelper $query) {
$query->where(['deleted' => 0]);
$query->like('name')->equal('status')->dateBetween('create_time');
});
}
/**
* 列表数据处理
* @param array $data
*/
protected function _page_filter(array &$data)
{
$data = DataExtend::arr2table($data);
}
/**
* 添加商品分类
* @auth true
*/
public function add()
{
PointsMallGoodsCate::mForm('form');
}
/**
* 编辑商品分类
* @auth true
*/
public function edit()
{
PointsMallGoodsCate::mForm('form');
}
/**
* 表单数据处理
* @param array $data
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
protected function _form_filter(array &$data)
{
if ($this->request->isGet()) {
$data['pid'] = intval($data['pid'] ?? input('pid', '0'));
$this->cates = PointsMallGoodsCate::pdata($this->maxLevel, $data, [
'id' => '0', 'pid' => '-1', 'name' => '顶部分类',
]);
}
}
/**
* 修改商品分类状态
* @auth true
*/
public function state()
{
PointsMallGoodsCate::mSave($this->_vali([
'status.in:0,1' => '状态值范围异常!',
'status.require' => '状态值不能为空!',
]));
}
/**
* 删除商品分类
* @auth true
*/
public function remove()
{
PointsMallGoodsCate::mDelete();
}
/**
* 商品分类选择器
* @login true
* @return void
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function select()
{
$this->get['status'] = 1;
$this->get['deleted'] = 0;
$this->index();
}
}

View File

@ -0,0 +1,138 @@
<?php
namespace plugin\points_mall\controller;
use plugin\account\model\PluginAccountUser;
use plugin\points_mall\model\PointsMallOrder;
use plugin\points_mall\service\UserOrderService;
use think\admin\Controller;
use think\admin\extend\CodeExtend;
use think\admin\helper\QueryHelper;
use think\exception\HttpResponseException;
class Order extends Controller
{
/**
* 订单数据管理
* @auth true
* @menu true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function index()
{
$this->type = trim($this->get['type'] ?? 'ta', 't');
PointsMallOrder::mQuery()->layTable(function (QueryHelper $query) {
$this->title = '订单数据管理';
$this->total = ['t0' => 0, 't1' => 0, 't2' => 0, 't3' => 0, 't4' => 0, 't5' => 0, 't6' => 0, 't7' => 0, 'ta' => 0];
$this->types = ['ta' => '全部订单', 't2' => '待支付', 't3' => '待审核', 't4' => '待发货', 't5' => '已发货', 't6' => '已收货', 't7' => '已评论', 't0' => '已取消'];
foreach ($query->db()->field('status,count(1) total')->group('status')->cursor() as $vo) {
[$this->total["t{$vo['status']}"] = $vo['total'], $this->total['ta'] += $vo['total']];
}
}, function (QueryHelper $query) {
$query->with(['user', 'from', 'items', 'address']);
$query->equal('status,refund_status')->like('order_no');
$query->dateBetween('create_time,payment_time,cancel_time,delivery_type');
// 用户搜索查询
$db = PluginAccountUser::mQuery()->like('phone|nickname#user_keys')->db();
if ($db->getOptions('where')) $query->whereRaw("unid in {$db->field('id')->buildSql()}");
// 列表选项卡
if (is_numeric($this->type)) {
$query->where(['status' => $this->type]);
}
// 分页排序处理
$query->where(['deleted_status' => 0]);
});
}
/**
* 单据凭证支付审核
* @auth true
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function audit()
{
if ($this->request->isGet()) {
PointsMallOrder::mForm('', 'order_no');
} else {
$data = $this->_vali([
'order_no.require' => '订单单号不能为空!',
'status.in:0,1' => '审核状态数值异常!',
'status.require' => '审核状态不能为空!',
'remark.default' => '',
]);
if (empty($data['status'])) {
$data['status'] = 0;
$data['cancel_status'] = 1;
$data['cancel_remark'] = $data['remark'] ?: '后台审核驳回并取消订单';
$data['cancel_time'] = date('Y-m-d H:i:s');
} else {
$data['status'] = 4;
$data['payment_code'] = CodeExtend::uniqidDate(16, 'T');
$data['payment_time'] = date('Y-m-d H:i:s');
$data['payment_status'] = 1;
$data['payment_remark'] = $data['remark'] ?: '后台审核支付凭证通过';
}
$order = PointsMallOrder::mk()->where(['order_no' => $data['order_no']])->findOrEmpty();
if ($order->isEmpty() || $order['status'] !== 3) $this->error('不允许操作审核!');
// 无需发货时的处理
if ($data['status'] === 4 && empty($order['delivery_type'])) $data['status'] = 6;
// 更新订单支付状态
$map = ['status' => 3, 'order_no' => $data['order_no']];
if (PointsMallOrder::mk()->strict(false)->where($map)->update($data) !== false) {
if (in_array($data['status'], [4, 5, 6])) {
$this->app->event->trigger('PluginPaymentSuccess', $data);
$this->success('订单审核通过成功!');
} else {
$this->app->event->trigger('PluginWemallOrderCancel', $order);
UserOrderService::stock($data['order_no']);
$this->success('审核驳回并取消成功!');
}
} else {
$this->error('订单审核失败!');
}
}
}
/**
* 取消未支付的订单
* @auth true
* @return void
*/
public function cancel()
{
$data = $this->_vali(['order_no.require' => '订单号不能为空!']);
$order = PointsMallOrder::mk()->where($data)->findOrEmpty();
if ($order->isEmpty()) $this->error('订单查询异常!');
try {
if (!in_array($order['status'], [1, 2, 3])) {
$this->error('订单不能取消!');
}
$result = $order->save([
'status' => 0,
'cancel_status' => 1,
'cancel_remark' => '后台取消未支付的订单',
'cancel_time' => date('Y-m-d H:i:s'),
]);
if ($result !== false) {
UserOrderService::stock($order['order_no']);
$this->app->event->trigger('PluginWemallOrderCancel', $order);
$this->success('取消未支付的订单成功!');
} else {
$this->error('取消支付的订单失败!');
}
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
$this->error($exception->getMessage());
}
}
}

View File

@ -7,6 +7,7 @@ use think\exception\HttpResponseException;
class Auth extends AuthController
{
protected $checkBind = false;
/**
* 控制器初始化
* @return void
@ -15,7 +16,7 @@ class Auth extends AuthController
{
try {
parent::initialize();
$this->checkUserStatus(false);
$this->checkUserStatus($this->checkBind);
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {

View File

@ -0,0 +1,95 @@
<?php
namespace plugin\points_mall\controller\api;
use plugin\points_mall\model\PointsMallGoods;
use plugin\points_mall\model\PointsMallGoodsCate;
use plugin\points_mall\model\PointsMallGoodsItem;
use think\admin\Controller;
use think\admin\extend\CodeExtend;
use think\admin\helper\QueryHelper;
use think\db\Query;
/**
* 商品数据管理
* @class Goods
* @package plugin\points_mall\controller\api
*/
class Goods extends Controller
{
/**
* 获取商品列表或详情
* @return void
*/
public function get()
{
$this->cnames = null;
PointsMallGoods::mQuery(null, function (QueryHelper $query) {
// 显示分类显示
if (!empty($vCates = input('cates'))) {
$cates = array_filter(PointsMallGoodsCate::items(), function ($v) use ($vCates) {
return $v['id'] == $vCates;
});
$this->cnames = null;
if (count($cates) > 0) {
$cate = array_pop($cates);
$this->cnames = array_combine($cate['ids'], $cate['names']);
}
}
$query->equal('code')->like('name#keys')->like('marks,cates', ',');
if (!empty($code = input('code'))) {
// 查询单个商品详情
$query->with(['discount', 'items', 'comments' => function (Query $query) {
$query->limit(2)->where(['status' => 1, 'deleted' => 0]);
}])->withCount(['comments' => function (Query $query) {
$query->where(['status' => 1, 'deleted' => 0]);
}]);
PointsMallGoods::mk()->where(['code' => $code])->inc('num_read')->update([]);
} else {
$query->with('discount')->withoutField('content');
}
// 数据排序处理
$sort = intval(input('sort', 0));
$type = intval(input('order', 0)) ? 'asc' : 'desc';
if ($sort === 1) {
$query->order("num_read {$type},sort {$type},id {$type}");
} elseif ($sort === 2) {
$query->order("price_selling {$type},sort {$type},id {$type}");
} else {
$query->order("sort {$type},id {$type}");
}
$query->where(['status' => 1, 'deleted' => 0]);
// 查询数据分页
$page = intval(input('page', 1));
$limit = max(min(intval(input('limit', 20)), 60), 1);
$this->success('获取商品数据', $query->page($page, false, false, $limit));
});
}
/**
* 数据结果处理
* @param array $data
* @param array $result
* @return void
*/
protected function _get_page_filter(array &$data, array &$result)
{
$result['cnames'] = $this->cnames ?? null;
}
/**
* 获取商品分类及标签
* @return void
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function cate()
{
$this->success('获取分类成功', [
'cate' => PointsMallGoodsCate::dtree(),
]);
}
}

View File

@ -0,0 +1,67 @@
<?php
namespace plugin\points_mall\controller\api\auth;
use plugin\points_mall\controller\api\Auth;
use plugin\points_mall\model\PointsMallGoods;
use plugin\points_mall\model\PointsMallGoodsItem;
use plugin\points_mall\model\PointsMallOrderCart;
use plugin\points_mall\service\UserActionService;
use think\admin\helper\QueryHelper;
use think\db\Query;
class Cart extends Auth
{
/**
* 获取购买车数据
* @return void
*/
public function get()
{
PointsMallOrderCart::mQuery(null, function (QueryHelper $query) {
$query->equal('ghash')->where(['unid' => $this->unid])->with([
'goods' => static function (Query $query) {
$query->with('items');
},
'specs' => static function (Query $query) {
$query->withoutField('id,create_time,update_time');
},
]);
$this->success('获取购买车数据!', $query->order('id desc')->page(false, false));
});
}
/**
* 修改购买车数据
* @return void
* @throws \think\db\exception\DbException
*/
public function set()
{
$data = $this->_vali([
'unid.value' => $this->unid,
'ghash.require' => '商品不能为空!',
'number.require' => '数量不能为空!',
]);
// 清理数量0的记录
$map = ['unid' => $this->unid, 'ghash' => $data['ghash']];
if ($data['number'] < 1) {
PointsMallOrderCart::mk()->where($map)->delete();
UserActionService::recount($this->unid);
$this->success('移除成功!');
}
// 检查商品是否存在
$gspec = PointsMallGoodsItem::mk()->where(['ghash' => $data['ghash']])->findOrEmpty();
$goods = PointsMallGoods::mk()->where(['code' => $gspec->getAttr('gcode')])->findOrEmpty();
if ($goods->isEmpty() || $gspec->isEmpty()) $this->error('商品不存在!');
// 保存商品数据
$data += ['gcode' => $gspec['gcode'], 'gspec' => $gspec['gspec']];
if (($cart = PointsMallOrderCart::mk()->where($map)->findOrEmpty())->save($data)) {
UserActionService::recount($this->unid);
$this->success('保存成功!', $cart->refresh()->toArray());
} else {
$this->error('保存失败!');
}
}
}

View File

@ -0,0 +1,509 @@
<?php
namespace plugin\points_mall\controller\api\auth;
use plugin\points_mall\controller\api\Auth;
use plugin\points_mall\model\PointsMallAddress;
use plugin\points_mall\model\PointsMallOrder;
use plugin\points_mall\model\PointsMallOrderCart;
use plugin\points_mall\model\PointsMallOrderItem;
use plugin\points_mall\service\GoodsService;
use plugin\points_mall\service\UserActionService;
use plugin\points_mall\service\UserOrderService;
use plugin\points_mall\service\UserPointService;
use think\admin\extend\CodeExtend;
use think\admin\helper\QueryHelper;
use think\db\Query;
use think\exception\HttpResponseException;
class Order extends Auth
{
protected $checkBind = true;
/**
* 获取订单数据
* @return void
*/
public function get()
{
PointsMallOrder::mQuery(null, function (QueryHelper $query) {
if (empty(input('order_no'))) {
$query->with('items')->where(['refund_status' => 0]);
} else {
$query->with(['items', 'address', 'sender', 'payments' => function (Query $query) {
$query->where(static function (Query $query) {
// $query->whereOr(['channel_type' => Payment::VOUCHER, 'payment_status' => 1, 'audit_status' => 1]);
$query->whereOr(['payment_status' => 1, 'audit_status' => 1]);
});
}]);
}
$query->in('status')->equal('order_no');
$query->where(['unid' => $this->unid, 'deleted_status' => 0])->order('id desc');
$this->success('获取订单成功!', $query->page(intval(input('page')), false, false, 10));
});
}
/**
* 创建订单数据
* @return void
*/
public function add()
{
try {
// 请求参数检查
$input = $this->_vali([
'carts.default' => '',
'rules.default' => '',
'agent.default' => '0',
]);
if (empty($input['rules']) && empty($input['carts'])) $this->error('参数无效!');
// 生成统一编号
do $extra = ['order_no' => $order['order_no'] = CodeExtend::uniqidNumber(16, 'N')];
while (PointsMallOrder::mk()->master()->where($extra)->findOrEmpty()->isExists());
[$items, $deliveryType] = [[], 0];
// 组装订单数据
foreach (GoodsService::parse($this->unid, trim($input['rules'], ':;'), $input['carts']) as $item) {
if (empty($item['count'])) continue;
if (empty($item['goods']) || empty($item['specs'])) $this->error('商品无效!');
[$goods, $gspec, $count] = [$item['goods'], $item['specs'], intval($item['count'])];
// 订单物流类型
if (empty($deliveryType) && $goods['delivery_code'] !== 'NONE') $deliveryType = 1;
// 限制购买数量
if (isset($goods['limit_maxnum']) && $goods['limit_maxnum'] > 0) {
$join = [PointsMallOrderItem::mk()->getTable() => 'b'];
$where = [['a.unid', '=', $this->unid], ['a.status', '>', 1], ['b.gcode', '=', $goods['code']]];
$buyCount = PointsMallOrder::mk()->alias('a')->join($join, 'a.order_no=b.order_no')->where($where)->sum('b.stock_sales');
if ($buyCount + $count > $goods['limit_maxnum']) $this->error('商品限购!');
}
// 限制购买身份
// if ($goods['limit_lowvip'] > $this->levelCode) $this->error('等级不够!');
// 商品库存检查
if ($gspec['stock_sales'] + $count > $gspec['stock_total']) $this->error('库存不足!');
// 订单详情处理
$items[] = [
'unid' => $order['unid'],
'order_no' => $order['order_no'],
// 商品字段
'gsku' => $gspec['gsku'],
'gname' => $goods['name'],
'gcode' => $gspec['gcode'],
'ghash' => $gspec['ghash'],
'gspec' => $gspec['gspec'],
'gunit' => $gspec['gunit'],
'gcover' => empty($gspec['gimage']) ? $goods['cover'] : $gspec['gimage'],
// 库存数量处理
'stock_sales' => $count,
// 快递发货数据
'delivery_code' => $goods['delivery_code'],
'delivery_count' => $goods['rebate_type'] > 0 ? $gspec['number_express'] * $count : 0,
// 商品费用字段
'price_cost' => $gspec['price_cost'],
'price_market' => $gspec['price_market'],
'price_selling' => $gspec['price_selling'],
// 商品费用统计
'total_price_cost' => $gspec['price_cost'] * $count,
'total_price_market' => $gspec['price_market'] * $count,
'total_price_selling' => $gspec['price_selling'] * $count,
'total_allow_balance' => $gspec['allow_balance'] * $count,
'total_allow_integral' => $gspec['allow_integral'] * $count,
'total_reward_balance' => $gspec['reward_balance'] * $count,
'total_reward_integral' => $gspec['reward_integral'] * $count,
];
}
// 默认使用销售销售
$order['rebate_amount'] = array_sum(array_column($items, 'rebate_amount'));
$order['allow_balance'] = array_sum(array_column($items, 'total_allow_balance'));
$order['allow_integral'] = array_sum(array_column($items, 'total_allow_integral'));
$order['reward_balance'] = array_sum(array_column($items, 'total_reward_balance'));
$order['reward_integral'] = array_sum(array_column($items, 'total_reward_integral'));
// 会员及代理升级
$order['level_agent'] = intval(max(array_column($items, 'level_agent')));
$order['level_member'] = intval(max(array_column($items, 'level_upgrade')));
// 订单发货类型
$order['status'] = $deliveryType ? 1 : 2;
$order['delivery_type'] = $deliveryType;
$order['ratio_integral'] = 100;
// 统计商品数量
$order['number_goods'] = array_sum(array_column($items, 'stock_sales'));
$order['number_express'] = array_sum(array_column($items, 'delivery_count'));
// 统计商品金额
$order['amount_cost'] = array_sum(array_column($items, 'total_price_cost'));
$order['amount_goods'] = array_sum(array_column($items, 'total_price_selling'));
// 折扣后的金额
$order['amount_discount'] = array_sum(array_column($items, 'discount_amount'));
$order['amount_reduct'] = $order['amount_goods'];
// 统计订单金额
$order['amount_real'] = round($order['amount_discount'] - $order['amount_reduct'], 2);
$order['amount_total'] = $order['amount_goods'];
$order['amount_profit'] = round($order['amount_real'] - $order['amount_cost']);
// 写入商品数据
$model = PointsMallOrder::mk();
$this->app->db->transaction(function () use ($order, $items, &$model) {
$model->save($order) && PointsMallOrderItem::mk()->saveAll($items);
// 设置收货地址
if ($order['delivery_type']) {
$where = ['unid' => $this->unid, 'deleted' => 0];
$address = PointsMallAddress::mk()->where($where)->order('type desc,id desc')->findOrEmpty();
$address->isExists() && UserOrderService::perfect($model->refresh(), $address);
}
});
// 同步库存销量
foreach (array_unique(array_column($items, 'gcode')) as $gcode) {
GoodsService::stock($gcode);
}
// 清理购物车数据
if (count($carts = str2arr($input['carts'])) > 0) {
PointsMallOrderCart::mk()->whereIn('id', $carts)->delete();
UserActionService::recount($this->unid);
}
// 触发订单创建事件
$this->app->event->trigger('PluginWemallOrderCreate', $order);
// 无需发货且无需支付,直接完成支付流程
if ($order['status'] === 2 && empty($order['amount_real'])) {
$this->success('下单成功!', $model->toArray());
}
// 返回处理成功数据
$this->success('下单成功!', array_merge($order, ['items' => $items]));
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
trace_file($exception);
$this->error("下单失败,{$exception->getMessage()}");
}
}
/**
* 模拟计算运费
* @return void
* @throws \think\admin\Exception
*/
// public function express()
// {
// $data = $this->_vali([
// 'unid.value' => $this->unid,
// 'order_no.require' => '单号不能为空!',
// 'address_id.require' => '地址不能为空!',
// ]);
//
// // 用户收货地址
// $map = ['unid' => $this->unid, 'id' => $data['address_id']];
// $addr = PointsMallAddress::mk()->where($map)->findOrEmpty();
// if ($addr->isEmpty()) $this->error('地址异常!');
//
// // 订单状态检查
// $map = ['unid' => $this->unid, 'order_no' => $data['order_no']];
// $tCount = intval(PointsMallOrderItem::mk()->where($map)->sum('delivery_count'));
//
// // 根据地址计算运费
// $map = ['status' => 1, 'deleted' => 0, 'order_no' => $data['order_no']];
// $tCode = PointsMallOrderItem::mk()->where($map)->column('delivery_code');
// [$amount, , , $remark] = ExpressService::amount($tCode, $addr['region_prov'], $addr['region_city'], $tCount);
// $this->success('计算运费!', ['amount' => $amount, 'remark' => $remark]);
// }
/**
* 确认收货地址
* @return void
* @throws \think\admin\Exception
*/
public function perfect()
{
$data = $this->_vali([
'unid.value' => $this->unid,
'order_no.require' => '单号不能为空',
'address_id.require' => '地址不能为空',
]);
// 用户收货地址
$where = ['id' => $data['address_id'], 'unid' => $this->unid, 'deleted' => 0];
$address = PointsMallAddress::mk()->where($where)->findOrEmpty();
if ($address->isEmpty()) $this->error('地址异常!');
// 订单状态检查
$where = ['unid' => $this->unid, 'order_no' => $data['order_no'], 'delivery_type' => 1];
$order = PointsMallOrder::mk()->where($where)->whereIn('status', [1, 2])->findOrEmpty();
if ($order->isEmpty()) $this->error('不能修改!');
// 更新订单收货地址
if (UserOrderService::perfect($order, $address)) {
$this->success('确认成功!', $order->refresh()->toArray());
} else {
$this->error('确认失败!');
}
}
/**
* 获取支付通道
* @return void
* @throws \think\admin\Exception
*/
// public function channel()
// {
// $this->success('获取支付通道!', [
// 'toratio' => Integral::ratio(),
// 'channels' => Payment::typesByAccess($this->type, true),
// ]);
// }
/**
* 获取支付参数
* @return void
*/
public function payment()
{
$data = $this->_vali([
'unid.value' => $this->unid,
'balance.default' => '0.00',
'integral.default' => '0',
'order_no.require' => '单号不能为空',
'order_ps.default' => '',
'coupon_code.default' => '', # 优惠券编号
'channel_code.require' => '支付不能为空',
'payment_back.default' => '', # 支付回跳地址
'payment_image.default' => '', # 支付凭证图片
]);
try {
$order = $this->getOrderModel();
$status = intval($order->getAttr('status'));
if ($status > 3) $this->success('已完成支付!');
if ($status === 3) $this->error('凭证待审核!');
if ($status !== 2) $this->error('不能发起支付!');
// 订单备注内容更新
empty($data['order_ps']) || $order->save(['order_ps' => $data['order_ps']]);
// 无需支付,直接完成订单
if (floatval($orderAmount = $order->getAttr('amount_real')) <= 0) {
$order->save(['status' => 4]);
$this->success('已支付成功!', []);
}
$leaveAmount = $orderAmount;
// 剩余支付金额
// if (($leaveAmount = Payment::leaveAmount($data['order_no'], $orderAmount)) <= 0) {
// $this->success('已完成支付!', PaymentResponse::mk(true, '已完成支付!')->toArray());
// }
// 扣除优惠券
// if (!empty($data['coupon_code']) && $data['coupon_code'] !== $order->getAttr('coupon_code')) try {
// // 检查优惠券是否有效
//// $where = ['unid' => $this->unid, 'status' => 1, 'deleted' => 0];
//// $coupon = PluginWemallUserCoupon::mk()->where($where)->with('bindCoupon')->findOrEmpty();
//// if ($coupon->isEmpty() || empty($coupon->getAttr('coupon_status')) || $coupon->getAttr('coupon_deleted') > 0) {
//// $this->error('无限优惠券!');
//// }
//// if ($coupon->getAttr('expire') > 0 && $coupon->getAttr('expire') < time()) $this->error('优惠券无效!');
//// if (floatval($coupon->getAttr('limit_amount')) <= $orderAmount) $this->error('未达到使用条件!');
//// [$couponCode, $couponAmount] = [strval($coupon->getAttr('code')), strval($coupon->getAttr('coupon_amount'))];
//// $response = Payment::mk(Payment::COUPON)->create($this->account, $data['order_no'], '优惠券抵扣', $orderAmount, $couponAmount, '', '', '', $couponCode);
//// $order->save(['coupon_code' => $couponCode, 'coupon_amount' => $couponAmount]);
//// $coupon->save(['used' => 1, 'status' => 2, 'used_time' => date('Y-m-d H:i:s')]);
//// if (($leaveAmount = Payment::leaveAmount($data['order_no'], $orderAmount)) <= 0) $this->success('已完成支付!', $response->toArray());
// } catch (HttpResponseException $exception) {
// throw $exception;
// } catch (\Exception $exception) {
// $this->error($exception->getMessage());
// }
// 积分抵扣处理
// if ($leaveAmount > 0 && $data['integral'] > 0) {
// if ($data['integral'] > $order->getAttr('allow_integral')) $this->error("超出积分抵扣!");
// if ($data['integral'] > Integral::recount($this->unid)['usable']) $this->error('账号积分不足!');
// $response = Payment::mk(payment::INTEGRAL)->create($this->account, $data['order_no'], '账号积分抵扣', $orderAmount, $data['integral']);
// if (($leaveAmount = Payment::leaveAmount($data['order_no'], $orderAmount)) <= 0) $this->success('已完成支付!', $response->toArray());
// }
$userPoint = UserPointService::getUserPoint($this->unid);
if ($userPoint['point'] < $leaveAmount) {
$this->error("积分不足!");
} else {
$order->save(['status' => 4]);
UserPointService::addUserPoint($this->unid, -$leaveAmount, '积分购买商品抵扣');
$this->success('积分抵扣成功!', []);
}
// 余额支付扣减
// if ($leaveAmount > 0 && $data['balance'] > 0) {
// if ($data['balance'] > $order->getAttr('allow_balance')) $this->error("超出余额限额!");
// if ($data['balance'] > Balance::recount($this->unid)['usable']) $this->error('账号余额不足!');
// $response = Payment::mk(Payment::BALANCE)->create($this->account, $data['order_no'], '账号余额支付!', $orderAmount, $data['balance']);
// if (($leaveAmount = Payment::leaveAmount($data['order_no'], $orderAmount)) <= 0) $this->success('已完成支付!', $response->toArray());
// }
// 凭证图片保存
// if (!empty($data['payment_image'])) {
// $data['payment_image'] = Storage::saveImage($data['payment_image'])['url'] ?? '';
// }
// 创建支付订单
// $response = Payment::mk($data['channel_code'])->create(
// $this->account, $data['order_no'], '商城订单支付',
// $orderAmount, strval($leaveAmount), '', $data['payment_back'], $data['payment_image']
// );
// 标准化返回结果
// if ($response->status) {
// $this->success($response->message, $response->toArray());
// } else {
// $this->error($response->message, $response->toArray());
// }
} catch (HttpResponseException $exception) {
throw $exception;
} catch (\Exception $exception) {
trace_file($exception);
$this->error($exception->getMessage());
}
}
/**
* 取消未支付订单
* @return void
* @throws \think\admin\Exception
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public function cancel()
{
$order = $this->getOrderModel();
if (in_array($order->getAttr('status'), [1, 2, 3])) {
$data = [
'status' => 0,
'cancel_time' => date('Y-m-d H:i:s'),
'cancel_status' => 1,
'cancel_remark' => '用户主动取消订单!',
];
if ($order->save($data) && UserOrderService::stock($order->getAttr('order_no'))) {
// 触发订单取消事件
Payment::refund($order->getAttr('order_no'));
$this->app->event->trigger('PluginWemallOrderCancel', $order);
// 返回处理成功数据
$this->success('取消成功!');
} else {
$this->error('取消失败!');
}
} else {
$this->error('不可取消!');
}
}
/**
* 删除已取消订单
* @return void
*/
public function remove()
{
$order = $this->getOrderModel();
if ($order->isEmpty()) $this->error('读取订单失败!');
if ($order->getAttr('status') == 0) {
if ($order->save([
'status' => 0,
'deleted_time' => date('Y-m-d H:i:s'),
'deleted_status' => 1,
'deleted_remark' => '用户主动删除订单!',
])) {
// 触发订单删除事件
$this->app->event->trigger('PluginWemallOrderRemove', $order);
// 返回处理成功数据
$this->success('删除成功!');
} else {
$this->error('删除失败!');
}
} else {
$this->error('不可删除!');
}
}
/**
* 订单确认收货
* @return void
*/
public function confirm()
{
$order = $this->getOrderModel();
if (in_array($order->getAttr('status'), [5, 6])) {
// 触发订单确认事件
$order->save([
'status' => 6,
'confirm_time' => date('Y-m-d H:i:s'),
'confirm_remark' => '用户主动确认签收订单!',
]);
$this->app->event->trigger('PluginWemallOrderConfirm', $order);
// 返回处理成功数据
$this->success('确认成功!');
} else {
$this->error('确认失败!');
}
}
/**
* 提交订单评论
* @return void
*/
// public function comment()
// {
// $order = $this->getOrderModel();
// if (in_array($order->getAttr('status'), [6, 7])) try {
// // 接收评论数据
// $items = json_decode($this->request->post('data'), true);
// $this->app->db->transaction(function () use ($order, $items) {
// $order->save(['status' => 7]);
// $order->items()->select()->map(function (PointsMallOrderItem $item) use ($items) {
// if (!empty($input = $items[$item->getAttr('ghash')])) {
// UserAction::comment($item, $input['rate'], $input['content'], $input['images']);
// }
// });
// });
// $this->success('评论成功!');
// } catch (HttpResponseException $exception) {
// throw $exception;
// } catch (\Exception $exception) {
// $this->error($exception->getMessage());
// } else {
// $this->error('无需评论!');
// }
// }
/**
* 订单状态统计
* @return void
*/
public function total()
{
$data = ['t0' => 0, 't1' => 0, 't2' => 0, 't3' => 0, 't4' => 0, 't5' => 0, 't6' => 0, 't7' => 0];
$query = PointsMallOrder::mk()->where(['unid' => $this->unid, 'refund_status' => 0, 'deleted_status' => 0]);
foreach ($query->field('status,count(1) count')->group('status')->cursor() as $item) {
$data["t{$item['status']}"] = $item['count'];
}
$this->success('获取统计!', $data);
}
/**
* 物流追踪查询
* @return void
*/
// public function track()
// {
// try {
// $data = $this->_vali([
// 'code.require' => '快递不能为空', 'number.require' => '单号不能为空'
// ]);
// $result = ExpressService::query($data['code'], $data['number']);
// empty($result['code']) ? $this->error($result['info']) : $this->success('快递追踪!', $result);
// } catch (HttpResponseException $exception) {
// throw $exception;
// } catch (\Exception $exception) {
// $this->error($exception->getMessage());
// }
// }
/**
* 获取输入订单模型
* @return PointsMallOrder
*/
private function getOrderModel(): PointsMallOrder
{
$map = $this->_vali(['unid.value' => $this->unid, 'order_no.require' => '单号不能为空']);
$order = PointsMallOrder::mk()->where($map)->findOrEmpty();
if ($order->isEmpty()) $this->error('读取订单失败!');
return $order;
}
}