截流自动化的商城平台
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SettlementLogic.php 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. <?php
  2. namespace app\shop\logic\finance;
  3. use app\common\basics\Logic;
  4. use app\common\enum\OrderEnum;
  5. use app\common\enum\PayEnum;
  6. use app\common\model\AfterSale;
  7. use app\common\model\order\Order;
  8. use app\common\model\shop\Shop;
  9. use app\common\model\shop\ShopAccountLog;
  10. use app\common\model\shop\ShopSettlement;
  11. use app\common\model\shop\ShopSettlementRecord;
  12. use app\common\server\ConfigServer;
  13. use app\common\server\ExportExcelServer;
  14. use think\Exception;
  15. use think\facade\Db;
  16. class SettlementLogic extends Logic
  17. {
  18. /**
  19. * @Notes: 结算列表
  20. * @Author: 张无忌
  21. * @param $get
  22. * @param $shop_id
  23. * @return array
  24. */
  25. public static function lists($get, $shop_id, $is_export = false)
  26. {
  27. try {
  28. $where[] = ['shop_id', '=', $shop_id];
  29. if (!empty($get['start_time']) and $get['start_time'])
  30. $where[] = ['start_time', '>=', strtotime($get['start_time'])];
  31. if (!empty($get['end_time']) and $get['end_time'])
  32. $where[] = ['end_time', '>=', strtotime($get['end_time'])];
  33. // 导出Excel
  34. if (true === $is_export) {
  35. return self::export($where);
  36. }
  37. $model = new ShopSettlement();
  38. $lists = $model->field(true)
  39. ->where($where)
  40. ->order('id', 'desc')
  41. ->paginate([
  42. 'page' => $get['page'],
  43. 'list_rows' => $get['limit'],
  44. 'var_page' => 'page'
  45. ])
  46. ->toArray();
  47. return ['count'=>$lists['total'], 'lists'=>$lists['data']];
  48. } catch (\Exception $e) {
  49. return ['error'=>$e->getMessage()];
  50. }
  51. }
  52. /**
  53. * @Notes: 结算详细
  54. * @Author: 张无忌
  55. * @param $get
  56. * @return array
  57. */
  58. public static function detail($get)
  59. {
  60. try {
  61. $where[] = ['settle_id', '=', (int)$get['settle_id']];
  62. if (!empty($get['order_sn']) and $get['order_sn'])
  63. $where[] = ['order_sn', 'like', '%'.$get['order_sn'].'%'];
  64. $model = new ShopSettlementRecord();
  65. $lists = $model->field(true)
  66. ->where($where)
  67. ->order('id', 'asc')
  68. ->paginate([
  69. 'page' => $get['page'],
  70. 'list_rows' => $get['limit'],
  71. 'var_page' => 'page'
  72. ])
  73. ->toArray();
  74. return ['count'=>$lists['total'], 'lists'=>$lists['data']];
  75. } catch (\Exception $e) {
  76. return ['error'=>$e->getMessage()];
  77. }
  78. }
  79. /**
  80. * @Notes: 提交结算
  81. * @Author: 张无忌
  82. * @param $shop_id
  83. * @return bool
  84. */
  85. public static function add($shop_id)
  86. {
  87. Db::startTrans();
  88. try {
  89. // 1、获取售后时长时间搓
  90. $time = time();
  91. $afterSaleTime = ConfigServer::get('transaction', 'order_after_sale_days', 7);
  92. $afterSaleTime = intval($afterSaleTime * 24 * 60 * 60);
  93. // 2、查询所有可结算订单
  94. $orders = (new Order())->field([
  95. 'id,order_sn,order_status,pay_status,refund_status,is_cancel',
  96. 'order_amount,refund_amount,distribution_money,confirm_take_time'
  97. ])
  98. ->whereRaw("confirm_take_time+$afterSaleTime < $time")
  99. ->where([
  100. ['shop_id', '=', $shop_id],
  101. ['settle_id', '=', 0],
  102. ['order_status', '=', OrderEnum::ORDER_STATUS_COMPLETE],
  103. ['pay_status', '=', OrderEnum::PAY_STATUS_PAID],
  104. ['confirm_take_time', '>', 0]
  105. ])->select()->toArray();
  106. if (!$orders) throw new Exception('暂无可结算订单金额');
  107. // 3、检测订单是否再售后
  108. $afterSale = (new AfterSale())->whereIn('order_id', array_column($orders, 'id'))
  109. ->whereIn('status', [
  110. AfterSale::STATUS_APPLY_REFUND,
  111. AfterSale::STATUS_WAIT_RETURN_GOODS,
  112. AfterSale::STATUS_WAIT_RECEIVE_GOODS,
  113. AfterSale::STATUS_WAIT_REFUND
  114. ])->where('del', 0)->select()->toArray();
  115. $afterSaleOrderIds = array_column($afterSale, 'order_id');
  116. $afterSaleOrderIds = array_unique($afterSaleOrderIds);
  117. if (!empty($afterSaleOrderIds)) {
  118. $orderIds = array_column($orders, 'id');
  119. if (count($orderIds) <= count($afterSaleOrderIds)) {
  120. throw new Exception('暂无可结算订单金额!');
  121. }
  122. }
  123. // 4、生成结算批次记录
  124. $settleSn = createSn('shop_settlement', 'settle_sn', 'JS');
  125. $settle = ShopSettlement::create(['shop_id'=>$shop_id, 'settle_sn'=>$settleSn, 'create_time'=>$time,]);
  126. $data = self::handleSettlementByOrder($orders, $settle, $time);
  127. // 5、回调更新结算批次信息
  128. ShopSettlement::update([
  129. 'deal_order_count' => $data['dealOrderCount'],
  130. 'business_money' => $data['businessMoney'] ,
  131. 'refund_order_money' => $data['refundOrderMoney'],
  132. 'after_sales_money' => $data['afterSalesMoney'],
  133. 'distribution_money' => $data['distributionMoney'],
  134. 'entry_account_money' => $data['entryAccountMoney'],
  135. 'trade_service_fee' => $data['totalTradeServiceFee'],
  136. 'trade_service_ratio' => $data['trade_service_ratio'],
  137. ], ['id'=>$settle['id']]);
  138. // 6、记录商家结算流水记录
  139. $logType = ShopAccountLog::settlement_add_money;
  140. ShopAccountLog::incData($shop_id, $logType, $data['entryAccountMoney'], -1, [
  141. 'source_id' => $settle['id'],
  142. 'source_sn' => $settleSn,
  143. 'remark' => '商家对账结算'
  144. ]);
  145. // 7、把钱记录到商家钱包
  146. Shop::update(['wallet'=>['inc', $data['entryAccountMoney']]], ['id'=>$shop_id]);
  147. Db::commit();
  148. return true;
  149. } catch (\Exception $e) {
  150. Db::rollback();
  151. static::$error = $e->getMessage();
  152. return false;
  153. }
  154. }
  155. /**
  156. * @Notes: 对订单进行结算
  157. * 实际入账金额 = (订单实付金额 - 分销金额 - 退款金额) * 交易服务费比例
  158. * @Author: 张无忌
  159. * @param $orders (订单列表数据)
  160. * @param $settle (结算单信息)
  161. * @param $time (当前时间戳)
  162. * @return array
  163. * @throws \Exception
  164. */
  165. private static function handleSettlementByOrder($orders, $settle, $time)
  166. {
  167. // 1、获取交易服务费比例
  168. $tradeServiceRatio = (new Shop())->where(['id'=>$settle['shop_id']])->value('trade_service_fee') ?? 0;
  169. // 2、结算数据汇总统计
  170. $data = [
  171. 'dealOrderCount' => 0, //总已结算成交订单数
  172. 'businessMoney' => 0, //总已结算营业额
  173. 'refundOrderMoney' => 0, //总退款订单金额
  174. 'afterSalesMoney' => 0, //总售后退款金额
  175. 'distributionMoney' => 0, //总已结算分销佣金金额
  176. 'entryAccountMoney' => 0, //总已结算入账金额
  177. 'totalTradeServiceFee' => 0, //总交易服务费费用
  178. 'trade_service_ratio' => $tradeServiceRatio //交易服务费比例(%)
  179. ];
  180. // 3、处理结算每个订单
  181. $settle_record = [];
  182. $orders_update = [];
  183. foreach ($orders as $order) {
  184. $afterSale = (new AfterSale())->where(['order_id'=>$order['id']])
  185. ->whereIn('status', [
  186. AfterSale::STATUS_APPLY_REFUND,
  187. AfterSale::STATUS_WAIT_RETURN_GOODS,
  188. AfterSale::STATUS_WAIT_RECEIVE_GOODS,
  189. AfterSale::STATUS_WAIT_REFUND
  190. ])->where('del',0)->findOrEmpty();
  191. if (!$afterSale->isEmpty()) {
  192. continue;
  193. }
  194. $data['dealOrderCount'] += 1;
  195. $data['businessMoney'] += $order['order_amount'];
  196. $data['refundOrderMoney'] += $order['is_cancel'] ? $order['refund_amount'] : 0;
  197. $data['afterSalesMoney'] += $order['is_cancel'] ? 0 : $order['refund_amount'];
  198. $data['distributionMoney'] += $order['distribution_money'];
  199. $orderMoney = $order['order_amount'] - $order['distribution_money'] - ($order['refund_amount'] ?: 0);
  200. $orderMoney = $orderMoney < 0 ? 0 : $orderMoney;
  201. $tradeServiceFee = $orderMoney * ($tradeServiceRatio / 100); // 本单交易服务费
  202. $actualGetMoney = $orderMoney - $tradeServiceFee; // 实际到账金额
  203. $entryAmount = $actualGetMoney;
  204. $data['entryAccountMoney'] += $actualGetMoney;
  205. $data['totalTradeServiceFee'] += $tradeServiceFee;
  206. $settle_record[] = [
  207. 'settle_id' => $settle['id'],
  208. 'order_id' => $order['id'],
  209. 'settle_sn' => $settle['settle_sn'],
  210. 'order_sn' => $order['order_sn'],
  211. 'order_amount' => $order['order_amount'],
  212. 'refund_amount' => $order['is_cancel'] ? ($order['refund_amount'] ? : 0) : 0,
  213. 'after_sales_amount' => $order['is_cancel'] ? 0 : ($order['refund_amount'] ? : 0),
  214. 'distribution_amount' => $order['distribution_money'],
  215. 'entry_account_amount' => $entryAmount,
  216. 'trade_service_fee' => $tradeServiceFee,
  217. 'trade_service_ratio' => $tradeServiceRatio,
  218. 'order_complete_time' => $order['confirm_take_time'],
  219. 'create_time' => $time
  220. ];
  221. $orders_update[] = [
  222. 'id' => $order['id'],
  223. 'settle_id' => $settle['id'],
  224. 'settle_amount' => $entryAmount,
  225. 'update_time' => $time
  226. ];
  227. }
  228. // 4、保存更新
  229. if (!empty($settle_record)) {
  230. (new ShopSettlementRecord())->saveAll($settle_record);
  231. (new Order())->saveAll($orders_update);
  232. }
  233. // 5、返回汇总数据
  234. return $data;
  235. }
  236. /**
  237. * @Notes: 结算统计
  238. * @return array
  239. */
  240. public static function statistics($shop_id = 0)
  241. {
  242. $where[] = ['shop_id', '=' , $shop_id];
  243. $modelOrder = new Order();;
  244. //已结算成交订单数
  245. $modelShopSettlement = new ShopSettlement();
  246. $settleOrederNum = $modelShopSettlement
  247. ->where($where)
  248. ->sum('deal_order_count');
  249. //已结算营业额
  250. $settleOrederAmount = $modelShopSettlement
  251. ->where($where)
  252. ->sum('business_money');
  253. //待结算营业额
  254. $settleOrederAmountWait = $modelOrder
  255. ->where([
  256. ['shop_id', '=' , $shop_id],
  257. ['pay_status', '>', PayEnum::UNPAID],
  258. ['settle_id', '=', OrderEnum::SETTLE_WAIT]
  259. ])
  260. ->sum('order_amount');
  261. //已结算分销佣金金额
  262. $settleDistributionAmount = $modelShopSettlement
  263. ->where($where)
  264. ->sum('distribution_money');
  265. //已结算入账金额
  266. $settleWithdrawalAmount = $modelShopSettlement
  267. ->where($where)
  268. ->sum('entry_account_money');
  269. //已结算交易服务费
  270. $settlePoundageAmount = $modelShopSettlement
  271. ->where($where)
  272. ->sum('trade_service_fee');
  273. return [
  274. 'settleOrederNum' => $settleOrederNum, //已结算成交订单数
  275. 'settleOrederAmount' => $settleOrederAmount, //已结算营业额
  276. 'settleOrederAmountWait' => $settleOrederAmountWait, //待结算营业额
  277. 'settleDistributionAmount' => $settleDistributionAmount, //已结算分销佣金金额
  278. 'settleWithdrawalAmount' => $settleWithdrawalAmount, //已结算入账金额
  279. 'settlePoundageAmount' => $settlePoundageAmount, //已结算交易服务费
  280. ];
  281. }
  282. /**
  283. * @notes 导出
  284. * @param $where
  285. * @return array|false
  286. * @author 段誉
  287. * @date 2022/4/24 11:59
  288. */
  289. public static function export($where)
  290. {
  291. try {
  292. $model = new ShopSettlement();
  293. $lists = $model->field(true)
  294. ->where($where)
  295. ->order('id', 'desc')
  296. ->select()
  297. ->toArray();
  298. $excelFields = [
  299. 'settle_sn' => '结算批次号',
  300. 'deal_order_count' => '已结算成交订单数',
  301. 'business_money' => '已结算营业额',
  302. 'refund_order_money' => '退款订单金额',
  303. 'after_sales_money' => '售后退款金额',
  304. 'distribution_money' => '已结算分销佣金金额',
  305. 'entry_account_money' => '已结算入账金额',
  306. 'create_time' => '结算时间',
  307. ];
  308. $export = new ExportExcelServer();
  309. $export->setFileName('财务结算');
  310. $export->setExportNumber(['settle_sn']);
  311. $result = $export->createExcel($excelFields, $lists);
  312. return ['url' => $result];
  313. } catch (\Exception $e) {
  314. self::$error = $e->getMessage();
  315. return false;
  316. }
  317. }
  318. }