|
|
@@ -1,16 +1,13 @@
|
|
|
<?php
|
|
|
/**
|
|
|
- * 售后资金/隔天售后辅助服务
|
|
|
- * 用途:资格校验、支付快照与资金三态(hasReturn/couldReturn/returnBalance)、隔天金额与返余额。
|
|
|
- * 字段:sameDay 区分当天/隔天;onlinePay/payWay 与原单一致;废弃 fundType。
|
|
|
+ * 隔天售后业务类(biz-ghs/order/classes)
|
|
|
+ * 用途:资格校验、支付快照与资金三态、隔天金额/返余额、统计净销量辅助。
|
|
|
+ * 调用方:RefundOrderClass、CgRefundClass、统计类、售后 Controller/Service。
|
|
|
*/
|
|
|
-namespace bizGhs\order\services;
|
|
|
+namespace bizGhs\order\classes;
|
|
|
|
|
|
use bizGhs\custom\classes\CustomClass;
|
|
|
use bizGhs\custom\services\GhsRechargeSettleService;
|
|
|
-use bizGhs\order\classes\OrderClass;
|
|
|
-use bizGhs\order\classes\RefundOrderClass;
|
|
|
-use bizGhs\order\classes\RefundOrderItemClass;
|
|
|
use bizGhs\product\classes\ProductClass;
|
|
|
use bizGhs\shop\classes\MainClass;
|
|
|
use bizGhs\stock\classes\StockRecordClass;
|
|
|
@@ -20,7 +17,7 @@ use common\components\dict;
|
|
|
use common\components\util;
|
|
|
use Yii;
|
|
|
|
|
|
-class NextDayRefundService
|
|
|
+class NextDayRefundClass
|
|
|
{
|
|
|
const SAME_DAY_YES = 1;
|
|
|
const SAME_DAY_NO = 0;
|
|
|
@@ -611,4 +608,273 @@ class NextDayRefundService
|
|
|
}
|
|
|
return $map;
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 支付日净销量:当天已退 = refundNum - nextRefundNum,净销 = xhNum - 当天已退。
|
|
|
+ * 隔天退货记在 nextRefundNum,不在支付日从销量扣掉(通过日再扣)。
|
|
|
+ *
|
|
|
+ * @param mixed $xhNum 下单数量
|
|
|
+ * @param mixed $refundNum 总已退
|
|
|
+ * @param mixed $nextRefundNum 隔天已退
|
|
|
+ * @return string
|
|
|
+ */
|
|
|
+ public static function payDayRemainNum($xhNum, $refundNum, $nextRefundNum = 0)
|
|
|
+ {
|
|
|
+ $sameDayRefund = bcsub((string)$refundNum, (string)($nextRefundNum ?? 0), 2);
|
|
|
+ if (bccomp($sameDayRefund, '0', 2) < 0) {
|
|
|
+ $sameDayRefund = '0';
|
|
|
+ }
|
|
|
+ return bcsub((string)$xhNum, $sameDayRefund, 2);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @deprecated 已改用订单行 nextRefundNum + payDayRemainNum,保留兼容旧调用
|
|
|
+ * 关联原单上「已发生」的隔天退货(不限通过日):用于销量按 payTime 统计时加回 refundNum 中的隔天部分,
|
|
|
+ * 避免与按 passTime 扣减重复;口径对齐客户业绩(支付日先全额,通过日再扣)。
|
|
|
+ *
|
|
|
+ * @param int $mainId
|
|
|
+ * @param string[] $relateOrderSns 原销售单号列表
|
|
|
+ * @return array productId => [num, amount]
|
|
|
+ */
|
|
|
+ public static function sumItemByProductForRelateOrderSns($mainId, $relateOrderSns)
|
|
|
+ {
|
|
|
+ $relateOrderSns = array_values(array_unique(array_filter($relateOrderSns)));
|
|
|
+ if (empty($relateOrderSns)) {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ $snParams = [];
|
|
|
+ foreach ($relateOrderSns as $i => $sn) {
|
|
|
+ $snParams[':sn' . $i] = $sn;
|
|
|
+ }
|
|
|
+ $in = implode(',', array_keys($snParams));
|
|
|
+ $sql = "SELECT i.productId, COALESCE(SUM(i.xhNum),0) AS num, COALESCE(SUM(i.xhPrice),0) AS amount
|
|
|
+ FROM xhRefundItem i
|
|
|
+ INNER JOIN xhRefund r ON r.orderSn = i.orderSn
|
|
|
+ WHERE r.mainId=:mainId AND r.status=:status AND r.sameDay=:sameDay
|
|
|
+ AND r.refundType=:rtype
|
|
|
+ AND r.relateOrderSn IN ($in)
|
|
|
+ GROUP BY i.productId";
|
|
|
+ $params = array_merge([
|
|
|
+ ':mainId' => $mainId,
|
|
|
+ ':status' => RefundOrderClass::STATUS_COMPLETE,
|
|
|
+ ':sameDay' => self::SAME_DAY_NO,
|
|
|
+ ':rtype' => RefundOrderClass::REFUND_TYPE_MONEY_GOOD,
|
|
|
+ ], $snParams);
|
|
|
+ $rows = Yii::$app->db->createCommand($sql, $params)->queryAll();
|
|
|
+ $map = [];
|
|
|
+ foreach ($rows as $row) {
|
|
|
+ $map[$row['productId']] = [
|
|
|
+ 'num' => bcadd($row['num'] ?? '0', '0', 2),
|
|
|
+ 'amount' => bcadd($row['amount'] ?? '0', '0', 2),
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ return $map;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 隔天「仅退款」按通过日汇总金额(无花材明细,进收支分类「销售仅退款」等)
|
|
|
+ */
|
|
|
+ public static function sumMoneyOnlyAmountByMainAndTime($mainId, $startTime, $endTime)
|
|
|
+ {
|
|
|
+ $sql = "SELECT COALESCE(SUM(refundPrice),0) AS total FROM xhRefund
|
|
|
+ WHERE mainId=:mainId AND status=:status AND sameDay=:sameDay
|
|
|
+ AND refundType=:rtype
|
|
|
+ AND IFNULL(NULLIF(passTime,'0000-00-00 00:00:00'), addTime) BETWEEN :start AND :end";
|
|
|
+ $row = Yii::$app->db->createCommand($sql, [
|
|
|
+ ':mainId' => $mainId,
|
|
|
+ ':status' => RefundOrderClass::STATUS_COMPLETE,
|
|
|
+ ':sameDay' => self::SAME_DAY_NO,
|
|
|
+ ':rtype' => RefundOrderClass::REFUND_TYPE_MONEY,
|
|
|
+ ':start' => $startTime,
|
|
|
+ ':end' => $endTime,
|
|
|
+ ])->queryOne();
|
|
|
+ return bcadd($row['total'] ?? '0', '0', 2);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 隔天「仅退款」按通过日分摊到原单花材(无明细时按原单行金额占比分摊 refundPrice)
|
|
|
+ * 花材销量页用:通过日扣金额,数量不扣。
|
|
|
+ *
|
|
|
+ * @return array productId => [num=>0, amount=>...]
|
|
|
+ */
|
|
|
+ public static function sumMoneyOnlyAmountByProduct($mainId, $startTime, $endTime)
|
|
|
+ {
|
|
|
+ $sql = "SELECT r.id, r.refundPrice, r.relateOrderSn
|
|
|
+ FROM xhRefund r
|
|
|
+ WHERE r.mainId=:mainId AND r.status=:status AND r.sameDay=:sameDay
|
|
|
+ AND r.refundType=:rtype
|
|
|
+ AND IFNULL(NULLIF(r.relateOrderSn,''), '') <> ''
|
|
|
+ AND IFNULL(NULLIF(r.passTime,'0000-00-00 00:00:00'), r.addTime) BETWEEN :start AND :end";
|
|
|
+ $rows = Yii::$app->db->createCommand($sql, [
|
|
|
+ ':mainId' => $mainId,
|
|
|
+ ':status' => RefundOrderClass::STATUS_COMPLETE,
|
|
|
+ ':sameDay' => self::SAME_DAY_NO,
|
|
|
+ ':rtype' => RefundOrderClass::REFUND_TYPE_MONEY,
|
|
|
+ ':start' => $startTime,
|
|
|
+ ':end' => $endTime,
|
|
|
+ ])->queryAll();
|
|
|
+ if (empty($rows)) {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ $map = [];
|
|
|
+ foreach ($rows as $row) {
|
|
|
+ $refundPrice = bcadd((string)($row['refundPrice'] ?? '0'), '0', 2);
|
|
|
+ if (bccomp($refundPrice, '0', 2) <= 0) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $relateSn = $row['relateOrderSn'] ?? '';
|
|
|
+ $items = \bizGhs\order\classes\OrderItemClass::getAllByCondition(
|
|
|
+ ['orderSn' => $relateSn],
|
|
|
+ null,
|
|
|
+ 'productId,xhNum,xhUnitPrice',
|
|
|
+ null,
|
|
|
+ true
|
|
|
+ );
|
|
|
+ if (empty($items)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $weights = [];
|
|
|
+ $weightSum = '0.00';
|
|
|
+ foreach ($items as $item) {
|
|
|
+ $pid = intval($item->productId ?? 0);
|
|
|
+ if ($pid <= 0) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $line = bcmul((string)($item->xhNum ?? '0'), (string)($item->xhUnitPrice ?? '0'), 2);
|
|
|
+ if (bccomp($line, '0', 2) <= 0) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $weights[$pid] = bcadd($weights[$pid] ?? '0', $line, 2);
|
|
|
+ $weightSum = bcadd($weightSum, $line, 2);
|
|
|
+ }
|
|
|
+ if (bccomp($weightSum, '0', 2) <= 0) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $allocated = '0.00';
|
|
|
+ $pids = array_keys($weights);
|
|
|
+ $last = count($pids) - 1;
|
|
|
+ foreach ($pids as $idx => $pid) {
|
|
|
+ if ($idx === $last) {
|
|
|
+ $part = bcsub($refundPrice, $allocated, 2);
|
|
|
+ } else {
|
|
|
+ $part = bcdiv(bcmul($refundPrice, $weights[$pid], 4), $weightSum, 2);
|
|
|
+ $allocated = bcadd($allocated, $part, 2);
|
|
|
+ }
|
|
|
+ if (!isset($map[$pid])) {
|
|
|
+ $map[$pid] = ['num' => '0.00', 'amount' => '0.00'];
|
|
|
+ }
|
|
|
+ $map[$pid]['amount'] = bcadd($map[$pid]['amount'], $part, 2);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return $map;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 按配送员汇总隔天退货数量/金额(通过日;原单 sendStaffId)
|
|
|
+ * @return array sendStaffId => [num, amount]
|
|
|
+ */
|
|
|
+ public static function sumItemBySendStaff($mainId, $startTime, $endTime)
|
|
|
+ {
|
|
|
+ $sql = "SELECT IFNULL(o.sendStaffId,0) AS sendStaffId,
|
|
|
+ COALESCE(SUM(i.xhNum),0) AS num, COALESCE(SUM(i.xhPrice),0) AS amount
|
|
|
+ FROM xhRefundItem i
|
|
|
+ INNER JOIN xhRefund r ON r.orderSn = i.orderSn
|
|
|
+ INNER JOIN xhGhsOrder o ON o.orderSn = r.relateOrderSn
|
|
|
+ WHERE r.mainId=:mainId AND r.status=:status AND r.sameDay=:sameDay
|
|
|
+ AND r.refundType=:rtype
|
|
|
+ AND IFNULL(NULLIF(r.passTime,'0000-00-00 00:00:00'), r.addTime) BETWEEN :start AND :end
|
|
|
+ GROUP BY IFNULL(o.sendStaffId,0)";
|
|
|
+ $rows = Yii::$app->db->createCommand($sql, [
|
|
|
+ ':mainId' => $mainId,
|
|
|
+ ':status' => RefundOrderClass::STATUS_COMPLETE,
|
|
|
+ ':sameDay' => self::SAME_DAY_NO,
|
|
|
+ ':rtype' => RefundOrderClass::REFUND_TYPE_MONEY_GOOD,
|
|
|
+ ':start' => $startTime,
|
|
|
+ ':end' => $endTime,
|
|
|
+ ])->queryAll();
|
|
|
+ return self::mapStaffNumAmount($rows);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @deprecated 已改用订单行 nextRefundNum + payDayRemainNum,保留兼容旧调用
|
|
|
+ * 关联原单上已发生的隔天退货,按配送员汇总(支付日统计加回用)
|
|
|
+ */
|
|
|
+ public static function sumItemBySendStaffForRelateOrderSns($mainId, $relateOrderSns)
|
|
|
+ {
|
|
|
+ $relateOrderSns = array_values(array_unique(array_filter($relateOrderSns)));
|
|
|
+ if (empty($relateOrderSns)) {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ $snParams = [];
|
|
|
+ foreach ($relateOrderSns as $i => $sn) {
|
|
|
+ $snParams[':sn' . $i] = $sn;
|
|
|
+ }
|
|
|
+ $in = implode(',', array_keys($snParams));
|
|
|
+ $sql = "SELECT IFNULL(o.sendStaffId,0) AS sendStaffId,
|
|
|
+ COALESCE(SUM(i.xhNum),0) AS num, COALESCE(SUM(i.xhPrice),0) AS amount
|
|
|
+ FROM xhRefundItem i
|
|
|
+ INNER JOIN xhRefund r ON r.orderSn = i.orderSn
|
|
|
+ INNER JOIN xhGhsOrder o ON o.orderSn = r.relateOrderSn
|
|
|
+ WHERE r.mainId=:mainId AND r.status=:status AND r.sameDay=:sameDay
|
|
|
+ AND r.refundType=:rtype
|
|
|
+ AND r.relateOrderSn IN ($in)
|
|
|
+ GROUP BY IFNULL(o.sendStaffId,0)";
|
|
|
+ $params = array_merge([
|
|
|
+ ':mainId' => $mainId,
|
|
|
+ ':status' => RefundOrderClass::STATUS_COMPLETE,
|
|
|
+ ':sameDay' => self::SAME_DAY_NO,
|
|
|
+ ':rtype' => RefundOrderClass::REFUND_TYPE_MONEY_GOOD,
|
|
|
+ ], $snParams);
|
|
|
+ $rows = Yii::$app->db->createCommand($sql, $params)->queryAll();
|
|
|
+ return self::mapStaffNumAmount($rows);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 隔天仅退款按配送员汇总金额(通过日)
|
|
|
+ */
|
|
|
+ public static function sumMoneyOnlyAmountBySendStaff($mainId, $startTime, $endTime)
|
|
|
+ {
|
|
|
+ $sql = "SELECT IFNULL(o.sendStaffId,0) AS sendStaffId, COALESCE(SUM(r.refundPrice),0) AS amount
|
|
|
+ FROM xhRefund r
|
|
|
+ INNER JOIN xhGhsOrder o ON o.orderSn = r.relateOrderSn
|
|
|
+ WHERE r.mainId=:mainId AND r.status=:status AND r.sameDay=:sameDay
|
|
|
+ AND r.refundType=:rtype
|
|
|
+ AND IFNULL(NULLIF(r.relateOrderSn,''), '') <> ''
|
|
|
+ AND IFNULL(NULLIF(r.passTime,'0000-00-00 00:00:00'), r.addTime) BETWEEN :start AND :end
|
|
|
+ GROUP BY IFNULL(o.sendStaffId,0)";
|
|
|
+ $rows = Yii::$app->db->createCommand($sql, [
|
|
|
+ ':mainId' => $mainId,
|
|
|
+ ':status' => RefundOrderClass::STATUS_COMPLETE,
|
|
|
+ ':sameDay' => self::SAME_DAY_NO,
|
|
|
+ ':rtype' => RefundOrderClass::REFUND_TYPE_MONEY,
|
|
|
+ ':start' => $startTime,
|
|
|
+ ':end' => $endTime,
|
|
|
+ ])->queryAll();
|
|
|
+ $map = [];
|
|
|
+ foreach ($rows as $row) {
|
|
|
+ $sid = intval($row['sendStaffId'] ?? 0);
|
|
|
+ $map[$sid] = [
|
|
|
+ 'num' => '0.00',
|
|
|
+ 'amount' => bcadd($row['amount'] ?? '0', '0', 2),
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ return $map;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * @param array $rows
|
|
|
+ * @return array
|
|
|
+ */
|
|
|
+ protected static function mapStaffNumAmount($rows)
|
|
|
+ {
|
|
|
+ $map = [];
|
|
|
+ foreach ($rows as $row) {
|
|
|
+ $sid = intval($row['sendStaffId'] ?? 0);
|
|
|
+ $map[$sid] = [
|
|
|
+ 'num' => bcadd($row['num'] ?? '0', '0', 2),
|
|
|
+ 'amount' => bcadd($row['amount'] ?? '0', '0', 2),
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ return $map;
|
|
|
+ }
|
|
|
}
|