DistributionOrderClass.php 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. <?php
  2. /**
  3. * 用途:订单分销记录业务(xhDistributionOrder)
  4. * 谁用:拉新客户-查看贡献明细(分红明细页)
  5. */
  6. namespace bizHd\distribution\classes;
  7. use bizHd\base\classes\BaseClass;
  8. use common\components\dateUtil;
  9. use common\components\util;
  10. use Yii;
  11. use yii\db\Query;
  12. class DistributionOrderClass extends BaseClass
  13. {
  14. public static $baseFile = '\bizHd\distribution\models\DistributionOrder';
  15. /**
  16. * 分销员分红订单列表(xhDistributionOrder)
  17. * @param int $shopId
  18. * @param int $distId 获佣分销员 xhCustom.id
  19. * @param int $buyerId 下单客户 xhCustom.id,0 表示不限下线
  20. * @return array
  21. * @throws \Exception
  22. */
  23. public static function getContribOrderList($shopId, $distId, $buyerId = 0)
  24. {
  25. $shopId = (int)$shopId;
  26. $distId = (int)$distId;
  27. $buyerId = (int)$buyerId;
  28. if ($distId < 0) {
  29. throw new \Exception('参数无效');
  30. }
  31. $get = Yii::$app->request->get();
  32. $settleStatus = isset($get['settleStatus']) ? trim($get['settleStatus']) : '';
  33. $keyword = isset($get['keyword']) ? trim($get['keyword']) : '';
  34. $searchTime = isset($get['searchTime']) ? trim($get['searchTime']) : 'thisMonth';
  35. $startTime = isset($get['startTime']) ? trim($get['startTime']) : '';
  36. $endTime = isset($get['endTime']) ? trim($get['endTime']) : '';
  37. $period = dateUtil::formatTime($searchTime, $startTime, $endTime);
  38. // 分红合计:与列表相同的 searchTime 时段、settleStatus(不含 keyword 分页条件)
  39. $monthQuery = (new Query())
  40. ->from('xhDistributionOrder')
  41. ->where(['shopId' => $shopId]);
  42. if ($distId > 0) {
  43. $monthQuery->andWhere(['distId' => $distId]);
  44. }
  45. if ($buyerId > 0) {
  46. $monthQuery->andWhere(['buyerId' => $buyerId]);
  47. }
  48. if ($settleStatus !== '' && $settleStatus !== 'all') {
  49. $monthQuery->andWhere(['settleStatus' => (int)$settleStatus]);
  50. }
  51. if (!empty($period['startTime']) && !empty($period['endTime'])) {
  52. $monthQuery->andWhere(['between', 'orderTime', $period['startTime'], $period['endTime']]);
  53. }
  54. $monthCommission = (float)$monthQuery->sum('commissionAmount');
  55. // Base::conditionQuery 不支持 or 组合,关键词搜索改用 Query 分页
  56. $page = isset($get['page']) ? max(1, (int)$get['page']) : 1;
  57. $pageSize = isset($get['pageSize']) && (int)$get['pageSize'] > 0
  58. ? (int)$get['pageSize']
  59. : (int)Yii::$app->params['pageSize'];
  60. $query = (new Query())
  61. ->from('xhDistributionOrder')
  62. ->where(['shopId' => $shopId]);
  63. if ($distId > 0) {
  64. $query->andWhere(['distId' => $distId]);
  65. }
  66. if ($buyerId > 0) {
  67. $query->andWhere(['buyerId' => $buyerId]);
  68. }
  69. if ($settleStatus !== '' && $settleStatus !== 'all') {
  70. $query->andWhere(['settleStatus' => (int)$settleStatus]);
  71. }
  72. if (!empty($period['startTime']) && !empty($period['endTime'])) {
  73. $query->andWhere(['between', 'orderTime', $period['startTime'], $period['endTime']]);
  74. }
  75. if ($keyword !== '') {
  76. $query->andWhere([
  77. 'or',
  78. ['like', 'orderSn', $keyword],
  79. ['like', 'buyerName', $keyword],
  80. ['like', 'distName', $keyword],
  81. ]);
  82. }
  83. $total = (int)(clone $query)->count('*', Yii::$app->db);
  84. $totalPage = $pageSize > 0 ? (int)ceil($total / $pageSize) : 0;
  85. $rows = $query
  86. ->orderBy(['orderTime' => SORT_DESC, 'id' => SORT_DESC])
  87. ->offset(($page - 1) * $pageSize)
  88. ->limit($pageSize)
  89. ->all(Yii::$app->db);
  90. $list = [];
  91. foreach ($rows as $row) {
  92. $list[] = self::formatContribOrderRow($row);
  93. }
  94. return [
  95. 'list' => $list,
  96. 'totalNum' => $total,
  97. 'totalPage' => $totalPage,
  98. 'moreData' => $page < $totalPage ? 1 : 0,
  99. 'monthCommission' => round($monthCommission, 2),
  100. ];
  101. }
  102. /**
  103. * 格式化贡献订单行(金额字段与库表一致,另附展示用文案)
  104. */
  105. protected static function formatContribOrderRow($row)
  106. {
  107. $settleStatus = (int)$row['settleStatus'];
  108. $commissionAmount = round((float)$row['commissionAmount'], 2);
  109. $isSettled = $settleStatus === 1;
  110. return [
  111. 'id' => (int)$row['id'],
  112. 'orderId' => (int)$row['orderId'],
  113. 'orderSn' => $row['orderSn'],
  114. 'buyerId' => (int)$row['buyerId'],
  115. 'buyerName' => $row['buyerName'],
  116. 'distId' => (int)$row['distId'],
  117. 'distName' => $row['distName'],
  118. 'orderAmount' => round((float)$row['orderAmount'], 2),
  119. 'payAmount' => round((float)$row['payAmount'], 2),
  120. 'sendCost' => round((float)$row['sendCost'], 2),
  121. 'commissionBase' => round((float)$row['commissionBase'], 2),
  122. 'commissionRate' => round((float)$row['commissionRate'], 2),
  123. 'commissionAmount' => $commissionAmount,
  124. 'bonusType' => (int)$row['bonusType'],
  125. 'bindDays' => (int)$row['bindDays'],
  126. 'settleStatus' => $settleStatus,
  127. 'orderTime' => $row['orderTime'],
  128. 'payTime' => $row['payTime'],
  129. 'finishTime' => $row['finishTime'],
  130. 'settleTime' => $row['settleTime'],
  131. 'invalidTime' => $row['invalidTime'],
  132. 'invalidReason' => $row['invalidReason'],
  133. 'amountText' => '+¥' . number_format($commissionAmount, 2, '.', ''),
  134. 'statusText' => self::settleStatusText($settleStatus),
  135. 'statusClass' => self::settleStatusClass($settleStatus),
  136. 'timeLabel' => $isSettled ? '结算时间' : '下单时间',
  137. 'timeValue' => $isSettled ? ($row['settleTime'] ?: $row['orderTime']) : $row['orderTime'],
  138. ];
  139. }
  140. protected static function settleStatusText($settleStatus)
  141. {
  142. $map = [
  143. 0 => '待结算',
  144. 1 => '已结算',
  145. 2 => '已失效',
  146. ];
  147. return isset($map[$settleStatus]) ? $map[$settleStatus] : '';
  148. }
  149. protected static function settleStatusClass($settleStatus)
  150. {
  151. if ($settleStatus === 0) {
  152. return 'pending';
  153. }
  154. if ($settleStatus === 1) {
  155. return 'success';
  156. }
  157. return 'invalid';
  158. }
  159. /**
  160. * 分销关联订单的售后期限校验:订单完成后超过 settleDays 天不可再发起退款
  161. * 无记录(与分销无关)或不存在 finishTime(尚未完成计佣)则放行
  162. * @param int $orderId xhOrder.id
  163. * @param int $shopId
  164. * @param int $mainId
  165. */
  166. public static function assertRefundNotExpired($orderId, $shopId, $mainId)
  167. {
  168. $orderId = (int)$orderId;
  169. if ($orderId <= 0) {
  170. return;
  171. }
  172. $distOrder = self::getByCondition(['orderId' => $orderId]);
  173. if (empty($distOrder)) {
  174. return;
  175. }
  176. $finishTime = $distOrder['finishTime'] ?? '';
  177. if (empty($finishTime) || $finishTime === '0000-00-00 00:00:00') {
  178. // 订单尚未写入完成时间,暂不按 settleDays 拦截
  179. return;
  180. }
  181. $rule = DistributionRuleClass::getRule((int)$shopId, (int)$mainId);
  182. $settleDays = max(0, (int)($rule['settleDays'] ?? 0));
  183. $deadline = strtotime($finishTime) + $settleDays * 86400;
  184. if (time() > $deadline) {
  185. util::fail("该订单已超过售后期限(完成后{$settleDays}天内可申请),无法再发起退款");
  186. }
  187. }
  188. /**
  189. * 订单完成后回写 finishTime(取值与 xhOrder.successTime 一致,不改 settleStatus)
  190. * @param int $orderId xhOrder.id
  191. * @param string|null $finishTime 默认当前时间
  192. * @return int 更新行数
  193. */
  194. public static function touchFinishTimeByOrderId($orderId, $finishTime = null)
  195. {
  196. $orderId = (int)$orderId;
  197. if ($orderId <= 0) {
  198. return 0;
  199. }
  200. $finishTime = $finishTime ?: date('Y-m-d H:i:s');
  201. return (int)self::$baseFile::updateAll(
  202. ['finishTime' => $finishTime],
  203. [
  204. 'and',
  205. ['orderId' => $orderId],
  206. ['settleStatus' => 0],
  207. ['>', 'commissionAmount', 0],
  208. ]
  209. );
  210. }
  211. }