|
|
<?php
|
|
|
|
|
|
namespace app\mall\service;
|
|
|
|
|
|
use app\distribution\logic\Commission;
|
|
|
use app\distribution\model\DistributionCommissionIncome;
|
|
|
use app\distribution\model\DistributionConfig;
|
|
|
use app\mall\model\MallCart;
|
|
|
use app\mall\model\MallOrder;
|
|
|
use app\mall\model\MallOrderProduct;
|
|
|
use app\mall\model\MallProduct;
|
|
|
use app\mall\model\MallProductSku;
|
|
|
use app\mall\model\MallSpikeProduct;
|
|
|
use app\mall\model\MallSpikeProductSku;
|
|
|
use app\money\logic\Money;
|
|
|
use Godruoyi\Snowflake\Snowflake;
|
|
|
use think\facade\Db;
|
|
|
use think\facade\Request;
|
|
|
|
|
|
class Order extends Base
|
|
|
{
|
|
|
|
|
|
/**
|
|
|
* 获取下单时购买商品数组列表
|
|
|
* @param int $buy_type 购买方式 1--购物车 2--立即购买
|
|
|
* @param int $product_id buy_type=2时,产品ID
|
|
|
* @param string $product_sku buy_type=2时,产品SKU
|
|
|
* @param int $number buy_type=2时,购买数量
|
|
|
* @param int $type 下单类型 1--商城 2--秒杀
|
|
|
* @param int $spike_product_id type=2时,秒杀产品ID
|
|
|
* @date 2022-10-13
|
|
|
*/
|
|
|
public function getOrderProduct($buy_type, $product_id = '', $product_sku = '', $number = 1, $type = 1, $spike_product_id = '')
|
|
|
{
|
|
|
$cart_model = new MallCart();
|
|
|
$product_model = new MallProduct();
|
|
|
$sku_model = new MallProductSku();
|
|
|
$spike_product_model = new MallSpikeProduct();
|
|
|
$spike_sku_model = new MallSpikeProductSku();
|
|
|
|
|
|
// 购物车结算
|
|
|
if ($buy_type == 1) {
|
|
|
$where = [
|
|
|
['uid', '=', $this->mid],
|
|
|
['user_id', '=', $this->userId],
|
|
|
// 是否选中 0-未选中 1--选中
|
|
|
['is_select', '=', 1],
|
|
|
// 是否失效 0--失效 1--有效
|
|
|
['is_effective', '=', 1]
|
|
|
];
|
|
|
$cart_product = $cart_model->getAllCart($where, 'id,product_id,is_product_spec_open,product_sku,number');
|
|
|
|
|
|
// 释放无用字段
|
|
|
foreach ($cart_product as $k => &$v) {
|
|
|
unset($v['product_is_publish']);
|
|
|
unset($v['product_delete_time']);
|
|
|
}
|
|
|
// 立即购买
|
|
|
} else if ($buy_type == 2) {
|
|
|
// 产品
|
|
|
$product = $product_model->getOneData([
|
|
|
['id', '=', $product_id],
|
|
|
['is_publish', '=', 1]
|
|
|
], 'id,name,is_spec_open,stock,cover_img,price,freight_type,freight_id,freight_money,weight');
|
|
|
|
|
|
// 商品有规格
|
|
|
if (!empty($product_sku)) {
|
|
|
$product_sku_list = $sku_model->getOneData([
|
|
|
['product_id', '=', $product_id],
|
|
|
['sku', '=', $product_sku],
|
|
|
], 'id,product_id,sku,cover_img,price,stock');
|
|
|
}
|
|
|
|
|
|
// 秒杀商城(秒杀商城只有立即购买)
|
|
|
if ($type == 2) {
|
|
|
// 秒杀商品
|
|
|
$spike_product = $spike_product_model->getOneData([
|
|
|
['id', '=', $spike_product_id]
|
|
|
]);
|
|
|
|
|
|
// 秒杀有规格
|
|
|
if (!empty($product_sku)) {
|
|
|
$spike_product_sku = $spike_sku_model->getOneData([
|
|
|
['spike_product_id', '=', $spike_product_id],
|
|
|
['sku', '=', $product_sku]
|
|
|
]);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
$cart_product[] = [
|
|
|
// 产品ID
|
|
|
'product_id' => $product['id'],
|
|
|
// 产品是否开启规格
|
|
|
'is_product_spec_open' => $product['is_spec_open'],
|
|
|
// 产品SKU
|
|
|
'product_sku' => $product_sku,
|
|
|
// 产品购买数量
|
|
|
'number' => $number,
|
|
|
// 产品名称
|
|
|
'product_name' => $product['name'],
|
|
|
// 产品SKU名称
|
|
|
'product_sku_name' => $product['is_spec_open'] == 0 ? '' : $product_sku_list['sku_name'],
|
|
|
// 产品封面图
|
|
|
'product_cover_img' => $product['cover_img'],
|
|
|
|
|
|
// 产品价钱
|
|
|
'product_price' => $product['is_spec_open'] == 0
|
|
|
? ($type == 1 ? $product['price'] : $spike_product['price_spike'])
|
|
|
: ($type == 1 ? $product_sku_list['price'] : $spike_product_sku['price_spike']),
|
|
|
|
|
|
// 产品库存
|
|
|
'product_stock' => $product['is_spec_open'] == 0
|
|
|
? ($type == 1 ? $product['stock'] : $spike_product['number'])
|
|
|
: ($type == 1 ? $product_sku_list['stock'] : $spike_product_sku['number']),
|
|
|
|
|
|
// 运费类型
|
|
|
'freight_type' => $product['freight_type'],
|
|
|
// 运费模板ID
|
|
|
'freight_id' => $product['freight_id'],
|
|
|
// 运费金额
|
|
|
'freight_money' => $product['freight_money'],
|
|
|
// 产品总重量
|
|
|
'weight' => $product['weight'],
|
|
|
// 秒杀产品ID 仅仅立即购买的时候有此字段
|
|
|
'spike_product_id' => $spike_product_id
|
|
|
];
|
|
|
|
|
|
}
|
|
|
return $cart_product;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 产品库存变动
|
|
|
* @param int $product_id 产品ID
|
|
|
* @param int $number 变动数量 >0 增加 <0 减少
|
|
|
* @param string $product_sku 产品SKU
|
|
|
* @param int $order_type 订单类型 1--商城订单 2--秒杀订单
|
|
|
* @param int $spike_product_id 秒杀产品ID
|
|
|
* @date 2022-10-21
|
|
|
*/
|
|
|
public function productStockChange($product_id, $number, $product_sku = '', $order_type = 1, $spike_product_id = '')
|
|
|
{
|
|
|
$product_model = new MallProduct();
|
|
|
$product_sku_model = new MallProductSku();
|
|
|
$spike_product_model = new MallSpikeProduct();
|
|
|
$spike_sku_model = new MallSpikeProductSku();
|
|
|
|
|
|
// 符号
|
|
|
$symbol = $number > 0 ? '+' : '-';
|
|
|
|
|
|
// 更新产品表库存
|
|
|
$product_update_data = [
|
|
|
'id' => $product_id,
|
|
|
'stock' => Db::raw('stock' . $symbol . abs($number))
|
|
|
];
|
|
|
$res = $product_model->dataUpdate($product_update_data);
|
|
|
if (!$res) {
|
|
|
return sendErrorArray(2001, '更新产品库存失败');
|
|
|
}
|
|
|
|
|
|
// 更新秒杀产品表库存
|
|
|
if ($order_type == 2) { //秒杀商城订单
|
|
|
$spike_product_update_data = [
|
|
|
'id' => $spike_product_id,
|
|
|
'number' => Db::raw('number' . $symbol . abs($number))
|
|
|
];
|
|
|
$res = $spike_product_model->dataUpdate($spike_product_update_data);
|
|
|
if (!$res) {
|
|
|
return sendErrorArray(2002, '更新秒杀产品库存失败');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 商品有SKU
|
|
|
if (!empty($product_sku)) {
|
|
|
// 获取SKU_ID
|
|
|
$sku_id = $product_sku_model->getOneData([
|
|
|
['product_id', '=', $product_id],
|
|
|
['sku', '=', $product_sku]
|
|
|
], 'id');
|
|
|
|
|
|
// 如果还能找到该规格项 则减库存 否则暂时不减
|
|
|
if (!empty($sku_id)) {
|
|
|
// 更改产品SKU库存
|
|
|
$product_data_sku = [
|
|
|
'stock' => Db::raw('stock' . $symbol . abs($number))
|
|
|
];
|
|
|
$res = $product_sku_model->dataUpdate($product_data_sku, [
|
|
|
['product_id', '=', $product_id],
|
|
|
['sku', '=', $product_sku]
|
|
|
]);
|
|
|
if (!$res) {
|
|
|
return sendErrorArray(2003, '更新产品SKU库存失败');
|
|
|
}
|
|
|
|
|
|
// 更改秒杀产品SKU库存
|
|
|
if ($order_type == 2) {
|
|
|
$spike_product_data_sku = [
|
|
|
'number' => Db::raw('number' . $symbol . abs($number))
|
|
|
];
|
|
|
$res = $spike_sku_model->dataUpdate($spike_product_data_sku, [
|
|
|
['spike_product_id', '=', $spike_product_id],
|
|
|
['sku', '=', $product_sku]
|
|
|
]);
|
|
|
if (!$res) {
|
|
|
return sendErrorArray(2004, '更新库存失败');
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return sendSuccessArray();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 产品销量变动
|
|
|
* @param int $product_id 产品ID
|
|
|
* @param int $number 变动数量 >0 增加 <0 减少
|
|
|
* @param int $order_type 订单类型 1--商城订单 2--秒杀订单
|
|
|
* @param int $spike_product_id 秒杀产品ID
|
|
|
* @date 2022-10-31
|
|
|
*/
|
|
|
public function productSalesChange($product_id, $number, $order_type = 1, $spike_product_id = '')
|
|
|
{
|
|
|
$product_model = new MallProduct();
|
|
|
$spike_product_model = new MallSpikeProduct();
|
|
|
|
|
|
$symbol = $number > 0 ? '+' : '-';
|
|
|
|
|
|
// 更新产品表销量
|
|
|
$product_update_data = [
|
|
|
'id' => $product_id,
|
|
|
'sales_actual_number' => Db::raw('sales_actual_number' . $symbol . abs($number))
|
|
|
];
|
|
|
$res = $product_model->dataUpdate($product_update_data);
|
|
|
if (!$res) {
|
|
|
return sendErrorArray(2001, '更新产品销量失败');
|
|
|
}
|
|
|
|
|
|
//更新秒杀产品表销量
|
|
|
if ($order_type == 2) {
|
|
|
$spike_product_update_data = [
|
|
|
'id' => $spike_product_id,
|
|
|
'sales_number' => Db::raw('sales_number' . $symbol . abs($number))
|
|
|
];
|
|
|
$res = $spike_product_model->dataUpdate($spike_product_update_data);
|
|
|
if (!$res) {
|
|
|
return sendErrorArray(2002, '更新秒杀产品销量失败');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return sendSuccessArray();
|
|
|
}
|
|
|
|
|
|
|
|
|
/**
|
|
|
* 订单支付成功
|
|
|
* @param int $order_id 订单ID
|
|
|
* @param string $transaction_id 微信支付环境:微信支付系统生成的订单号 支付宝支付环境:支付宝交易号
|
|
|
* @date 2022-10-21
|
|
|
*/
|
|
|
public function afterOrderPaySuccess($order_id, $transaction_id = '')
|
|
|
{
|
|
|
$order_model = new MallOrder();
|
|
|
$order_product_model = new MallOrderProduct();
|
|
|
$income_model = new DistributionCommissionIncome();
|
|
|
$config_model = new DistributionConfig();
|
|
|
$commission_logic = new Commission();
|
|
|
$snow_flake_class = new Snowflake();
|
|
|
|
|
|
// 查找订单
|
|
|
$order = $order_model->getOneData([
|
|
|
['id', '=', $order_id]
|
|
|
], 'id,uid,user_agent,type,user_id,pay_money');
|
|
|
|
|
|
// 1 - 更改订单状态
|
|
|
$data_update = [
|
|
|
'id' => $order['id'],
|
|
|
'is_pay' => 1,
|
|
|
'pay_time' => time(),
|
|
|
'status' => 2,
|
|
|
'transaction_id' => $transaction_id
|
|
|
];
|
|
|
|
|
|
$res = $order_model->dataUpdate($data_update);
|
|
|
if (!$res) {
|
|
|
return sendErrorArray(2001, '订单状态修改失败');
|
|
|
}
|
|
|
|
|
|
// 订单产品表
|
|
|
$order_product = $order_product_model->getAllData([
|
|
|
['order_id', '=', $order_id]
|
|
|
], 'id,product_id,spike_product_id,number');
|
|
|
|
|
|
// 2 - 付款之后,产品增加销量
|
|
|
foreach ($order_product as $k => $v) {
|
|
|
$res = $this->productSalesChange($v['product_id'], $v['number'], $order['type'], $v['spike_product_id']);
|
|
|
if ($res['code'] != 0) {
|
|
|
return $res;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 3 - 存入佣金收入表(佣金在路上)
|
|
|
if ($order['pay_money']) {
|
|
|
// 查找订单产品表的购买商品的名称
|
|
|
$product_name_arr = array_column($order_product->toArray(), 'product_name');
|
|
|
$product_name = implode(',', $product_name_arr);
|
|
|
|
|
|
// 查找分销比例
|
|
|
$config = $config_model->getOneData([
|
|
|
['uid', '=', $order['uid']]
|
|
|
], 'first_percent,first_commission,second_percent,second_commission,third_percent,third_commission');
|
|
|
|
|
|
// 获取上三级以及分销佣金
|
|
|
$commission = $commission_logic->getCommission($order['pay_money'], $order['user_id'], $config);
|
|
|
foreach ($commission as $k => $v) {
|
|
|
$data_income[] = [
|
|
|
'id' => $snow_flake_class->id(),
|
|
|
'uid' => $order['uid'],
|
|
|
'user_agent' => $order['user_agent'],
|
|
|
'user_id' => $order['user_id'],
|
|
|
'distributor_user_id' => $v['user_id'],
|
|
|
'relation_type' => 2,
|
|
|
'money' => $order['pay_money'],
|
|
|
'commission' => $v['commission'],
|
|
|
'rank' => $k + 1,
|
|
|
'show_text' => '购买商品"' . $product_name . '"',
|
|
|
'status' => 1,
|
|
|
'remark' => serialize([
|
|
|
'mall_order_id' => $order['id']
|
|
|
]),
|
|
|
'create_time' => time(),
|
|
|
'update_time' => time()
|
|
|
];
|
|
|
}
|
|
|
if (!empty($data_income)) {
|
|
|
$res = $income_model->insertAll($data_income);
|
|
|
if (!$res) {
|
|
|
return sendErrorArray(2002, '生成佣金记录失败');
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 4 - 统计系统 - 新增订单信息
|
|
|
$statistics_class = new \jucheng\tongji\Statistics();
|
|
|
$statistics_class->updateOrderInfo($order['pay_money']);
|
|
|
|
|
|
return sendSuccessArray();
|
|
|
}
|
|
|
|
|
|
|
|
|
/**
|
|
|
* 调起支付
|
|
|
* @param int $order_id 订单ID
|
|
|
* @date 2022-10-26
|
|
|
*/
|
|
|
public function createPayOrder($order_id)
|
|
|
{
|
|
|
$order_model = new MallOrder();
|
|
|
|
|
|
// 获取订单信息
|
|
|
$order = $order_model->getOneData([
|
|
|
['id', '=', $order_id]
|
|
|
], 'id,user_agent,user_id,order_number,pay_type,pay_money');
|
|
|
|
|
|
// 调起支付
|
|
|
switch ($order['pay_type']) {
|
|
|
// 微信支付
|
|
|
case 1:
|
|
|
$wxpay_param = get_wxpay_config_with_weixin($order['user_agent']);
|
|
|
$wxpay_class = new \tencent\wechat\pay\Wxpay($wxpay_param);
|
|
|
$openid = $this->openid;
|
|
|
$notify_url = Request::domain() . '/index.php/mall/api/Callback/weixinNotify/agent/' . $order['user_agent'] . '/uid/' . $this->mid;
|
|
|
|
|
|
// 生成支付订单
|
|
|
$result = $wxpay_class->createOrder($openid, $order['pay_money'], $order['order_number'], '商城支付订单', $notify_url, $order['user_agent']);
|
|
|
|
|
|
if ($result['return_code'] == 'FAIL' || $result['result_code'] == 'FAIL') {
|
|
|
return sendErrorArray(3100, $result['return_code'] != 'SUCCESS' ? $result['return_msg'] : $result['err_code_des']);
|
|
|
}
|
|
|
|
|
|
/* --H5平台微信支付--
|
|
|
直接返回 */
|
|
|
if ($order['user_agent'] == 'h5') {
|
|
|
// mweb_url为拉起微信支付收银台的中间页面,可通过访问该url来拉起微信客户端,完成支付,mweb_url的有效期为5分钟
|
|
|
return sendSuccessArray(['need_pay' => 1, 'pay_params' => $result['mweb_url']]);
|
|
|
}
|
|
|
|
|
|
/* --其他平台微信支付--
|
|
|
获取支付参数 */
|
|
|
$result_pay = $wxpay_class->wxPay($result['prepay_id'], $order['user_agent']);
|
|
|
|
|
|
return sendSuccessArray([
|
|
|
// 是否需要支付
|
|
|
'need_pay' => 1,
|
|
|
// 支付参数
|
|
|
'pay_params' => $result_pay
|
|
|
]);
|
|
|
break;
|
|
|
// $fubei_param = get_fubei_config();
|
|
|
// switch ($order['user_agent']) {
|
|
|
// // app 支付宝支付
|
|
|
// case 'mp_weixin':
|
|
|
// $mp_weixin_param = get_mp_weixin_config();
|
|
|
// $fubei_param['sub_appid'] = $mp_weixin_param['app_id'];
|
|
|
// break;
|
|
|
// case 'weixin':
|
|
|
// $weixin_param = get_weixin_config();
|
|
|
// $fubei_param['sub_appid'] = $weixin_param['app_id'];
|
|
|
// break;
|
|
|
// }
|
|
|
// $pay_class = new \fubei\pay\Pay($fubei_param);
|
|
|
// $openid = $this->openid;
|
|
|
// $notify_url = Request::domain() . '/index.php/mall/api/Callback/fubeiNotify/agent/' . $order['user_agent'] . '/uid/' . $this->mid;
|
|
|
// $result = $pay_class->pay($openid, $order['pay_money'], $order['order_number'], $order['fubri_order_number'], '商城支付订单', $notify_url, $fubei_param['store_id'], $order['user_agent']);
|
|
|
//
|
|
|
// // 没有调起支付,返回报错
|
|
|
// if ($result['result_code'] != 200) {
|
|
|
// return sendErrorArray($result['result_code'], $result['result_message']);
|
|
|
// }
|
|
|
// return sendSuccessArray([
|
|
|
// // 是否需要支付
|
|
|
// 'need_pay' => 1,
|
|
|
// // 支付参数
|
|
|
// 'pay_params' => $result['data']['sign_package']
|
|
|
// ]);
|
|
|
// break;
|
|
|
// 支付宝支付
|
|
|
case 2:
|
|
|
switch ($order['user_agent']) {
|
|
|
// app 支付宝支付
|
|
|
case 'app':
|
|
|
$ali_pay_param = get_app_alipay_config();
|
|
|
$ali_pay_class = new \ali\alipay\pay\AliPay($ali_pay_param);
|
|
|
|
|
|
$notify_url = Request::domain() . '/index.php/mall/api/Callback/alipayNotify/agent/' . $order['user_agent'] . '/uid/' . $this->mid;
|
|
|
$result = $ali_pay_class->aliPay($order['pay_money'], $order['order_number'], '商城支付订单', $notify_url);
|
|
|
|
|
|
if (empty($result['body'])) {
|
|
|
return sendErrorArray(3101, '生成支付宝订单失败');
|
|
|
}
|
|
|
|
|
|
return sendSuccessArray([
|
|
|
'need_pay' => 1,
|
|
|
'pay_params' => $result['body']
|
|
|
]);
|
|
|
break;
|
|
|
// 支付宝小程序 支付宝支付
|
|
|
case 'mp_alipay':
|
|
|
$ali_pay_param = get_mp_alipay_config();
|
|
|
$ali_pay_class = new \ali\alipay\pay\AliPay($ali_pay_param);
|
|
|
|
|
|
$notify_url = Request::domain() . '/index.php/mall/api/Callback/alipayNotify/agent/' . $order['user_agent'] . '/uid/' . $this->mid;
|
|
|
|
|
|
// 统一下单
|
|
|
$result = $ali_pay_class->mpAliPay($order['pay_money'], $order['order_number'], $this->openid, '商城支付订单', $notify_url);
|
|
|
|
|
|
if ($result['code'] != 10000) {
|
|
|
return sendErrorArray($result['code'], $result['sub_msg']);
|
|
|
}
|
|
|
|
|
|
return sendSuccessArray(['need_pay' => 1, 'pay_params' => $result['trade_no']]);
|
|
|
break;
|
|
|
// H5 支付宝支付
|
|
|
case 'h5':
|
|
|
$ali_pay_param = get_h5_alipay_config();
|
|
|
$ali_pay_class = new \ali\alipay\pay\AliPay($ali_pay_param);
|
|
|
|
|
|
$notify_url = Request::domain() . '/index.php/mall/api/Callback/alipayNotify/agent/' . $order['user_agent'] . '/uid/' . $this->mid;
|
|
|
// 用户付款中途退出返回商户网站的地址 添加该参数后在H5支付收银台会出现返回按钮,可用于用户付款中途退出并返回到该参数指定的商家网站地址
|
|
|
$quit_url = Request::domain() . '/h5/#/pages/mall/my/orderList';
|
|
|
$return_url = $quit_url;
|
|
|
|
|
|
// 统一下单
|
|
|
$result = $ali_pay_class->h5AliPay($order['pay_money'], $order['order_number'], '商城支付订单', $quit_url, $return_url, $notify_url);
|
|
|
|
|
|
if (empty($result['body'])) {
|
|
|
return sendErrorArray(2001, '生成支付宝订单失败');
|
|
|
}
|
|
|
|
|
|
return sendSuccessArray(['need_pay' => 1, 'pay_params' => $result['body']]);
|
|
|
break;
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
break;
|
|
|
// 余额支付
|
|
|
case 3:
|
|
|
$money_service = new \app\money\service\Money();
|
|
|
|
|
|
Db::startTrans();
|
|
|
//支付成功
|
|
|
$res = $this->afterOrderPaySuccess($order_id);
|
|
|
if ($res['code'] != 0) {
|
|
|
Db::rollback();
|
|
|
return $res;
|
|
|
}
|
|
|
// 扣除余额
|
|
|
$res = $money_service->change($order['user_id'], 2, -$order['pay_money'], '商城购物', $order['order_number'], [
|
|
|
'mall_order_id' => $order_id
|
|
|
]);
|
|
|
if ($res['code'] != 0) {
|
|
|
Db::rollback();
|
|
|
return $res;
|
|
|
}
|
|
|
|
|
|
Db::commit();
|
|
|
return sendSuccessArray(['need_pay' => 0], '支付成功');
|
|
|
break;
|
|
|
// 其他
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
}
|