diff --git a/app/libs/controller/order/class.LogisticsController.php b/app/libs/controller/order/class.LogisticsController.php new file mode 100644 index 0000000..fc7cb9e --- /dev/null +++ b/app/libs/controller/order/class.LogisticsController.php @@ -0,0 +1,18 @@ +orderService = OrderService::instance(); + $this->orderPrintService = OrderPrintService::instance(); + $this->orderMergeService = OrderMergeService::instance(); + } +} \ No newline at end of file diff --git a/app/libs/daos/AfterSale/AfterSalesDao.php b/app/libs/daos/AfterSale/AfterSalesDao.php index fd8f558..99bcddb 100644 --- a/app/libs/daos/AfterSale/AfterSalesDao.php +++ b/app/libs/daos/AfterSale/AfterSalesDao.php @@ -2,7 +2,223 @@ namespace Dao\AfterSale; +use AfterSalesConst; use Dao\AbstractDao; +use Dao\Order\OpOrderDao; +use Dao\Order\OpOrderExtDao; +use Dao\Order\OpOrderGoodsDao; +use Dao\PurchaseOrder\PurchaseOrderDao; +use RedisExt; +use RedisKeyConst; +use StatusConst; +use ZcArrayHelper; class AfterSalesDao extends AbstractDao { + public function searchPage($mallId, $filter, $page, $pageSize, $isNeedCheckSlowQuery) { + $mallIds = $filter['authMallIds'] ? $filter['authMallIds'] : array($mallId); + list($conditions, $joinTables, $orderByString) = $this->getSearchCondition($filter, $mallIds); + $whereStr = !empty($conditions) ? implode(' ', $conditions) : ''; + $joinStr = !empty($joinTables) ? implode(' ', $joinTables) : ''; + + $opOrderTbl = OpOrderDao::tableName(); + + $sql = $this->prepare("SELECT afs.* FROM %b o %l where o.mall_id in %li %l group by afs.`after_sales_id` %l", $this->getTable(), $joinStr, $mallIds, $whereStr, $orderByString); + if ($isNeedCheckSlowQuery && !isset($filter['orderSn']) && !isset($filter['afterSalesId']) && $this->checkIsSlowQuery($sql)) { + return [[], 0, 1]; + } + + list($afterSalesList, $total) = $this->queryPage("SELECT afs.* FROM %b o %l where o.mall_id in %li %l group by afs.`after_sales_id` %l", $opOrderTbl, $joinStr, $mallIds, $whereStr, $orderByString, $page, $pageSize); + \Zc::getLog('sqlDebug')->info('sql: ' . $this->lastSql()); + + return [$afterSalesList, $total, 0]; + } + + public function checkIsSlowQuery($sql, $limit = 150000) { + $slowQueryRedisKey = RedisKeyConst::buildSlowQueryKey(md5($sql)); + $bizRedis = RedisExt::factory('bizCache'); + + if ($bizRedis->get($slowQueryRedisKey)) { + return true; + } + + + $rows = $this->query($sql); + if (empty($rows) || !is_array($rows)) { + return false; + } + $isSlowQuery = false; + foreach ($rows as $row) { + if ($row['rows'] > $limit) { + $isSlowQuery = true; + \Zc::getLog('slowQueryDebug')->info("sql: {$sql}"); + $bizRedis->setex($slowQueryRedisKey, 3600, 1); + break; + } + } + + return $isSlowQuery; + } + + private function getSearchCondition($filter, $mallIds) { + $wheres = []; + $joinTables = []; + $orderByString = ''; + + $afterSalesTbl = $this->getTable(); + $opOrderGoodsTbl = OpOrderGoodsDao::tableName(); + $opOrderExtTbl = OpOrderExtDao::tableName(); + $purchaseOrderTbl = PurchaseOrderDao::tableName(); + + $joinTables[$afterSalesTbl] = $this->prepare('inner join %b afs on o.order_sn = afs.order_sn', $afterSalesTbl); + + if (!empty($filter['afterSalesStatus'])) { + $afterSalesStatusFilter = is_array($filter['afterSalesStatus']) ? $filter['afterSalesStatus'] : [$filter['afterSalesStatus']]; + $wheres[] = $this->prepare('and afs.after_sales_status in %li', $afterSalesStatusFilter); + } + if (isset($filter['shippingStatus']) && is_numeric($filter['shippingStatus'])) { + $wheres[] = $this->prepare('and afs.shipping_status = %i', $filter['shippingStatus']); + } + if (isset($filter['afterSalesType']) && is_numeric($filter['afterSalesType'])) { + $wheres[] = $this->prepare('and afs.after_sales_type = %i', $filter['afterSalesType']); + } + if (!empty($filter['orderSn'])) { + $wheres[] = $this->prepare('and afs.order_sn in %ls', $filter['orderSn']); + } + if (!empty($filter['afterSalesId'])) { + $wheres[] = $this->prepare('and afs.after_sales_id in %ls', $filter['afterSalesId']); + } + if (!empty($filter['goodsId'])) { + $joinTables[$opOrderGoodsTbl] = $this->prepare('left join %b oog on oog.order_id = o.order_id', $opOrderGoodsTbl); + $wheres[] = $this->prepare('and oog.goods_id = %i', $filter['goodsId']); + } + if (!empty($filter['trackingNumbers'])) { + $wheres[] = $this->prepare('and afs.tracking_number IN %ls', $filter['trackingNumbers']); + } + if (!empty($filter['recreatedAtStart'])) { + $wheres[] = $this->prepare("AND afs.`recreated_at` >= %s", $filter['recreatedAtStart']); + } + if (!empty($filter['recreatedAtEnd'])) { + $wheres[] = $this->prepare("AND afs.`recreated_at` <= %s", $filter['recreatedAtEnd']); + } + if (!empty($filter['expireStartTime'])) { + $wheres[] = $this->prepare("AND afs.`expire_time` >= %s", $filter['expireStartTime']); + } + if (!empty($filter['expireEndTime'])) { + $wheres[] = $this->prepare("AND afs.`expire_time` <= %s", $filter['expireEndTime']); + } + + if (!empty($filter['mallNote'])) { + $wheres[] = $this->prepare('AND afs.`mall_note` like %ss', $filter['mallNote']); + } + + if (isset($filter['hasMallNote']) && is_numeric($filter['hasMallNote'])) { + if ($filter['hasMallNote']) { + $wheres[] = $this->prepare("AND afs.`mall_note` != ''"); + } else { + $wheres[] = $this->prepare("AND afs.`mall_note` = ''"); + } + } + + if (!empty($filter['mallNoteFlag'])) { + $wheres[] = $this->prepare("AND afs.`mall_note_flag` IN %li", (is_array($filter['mallNoteFlag']) ? $filter['mallNoteFlag'] : [$filter['mallNoteFlag']])); + } + + if (!empty($filter['purchaseStartTime'])) { + $wheres[] = $this->prepare("AND po.`purchase_order_start_time` >= %s", $filter['purchaseStartTime']); + $joinTables['purchase_order'] = $this->prepare('LEFT JOIN purchase_order po ON po.`order_id` = o.`order_id`'); + } + if (!empty($filter['purchaseEndTime'])) { + $wheres[] = $this->prepare("AND po.`purchase_order_start_time` <= %s", $filter['purchaseEndTime']); + $joinTables['purchase_order'] = $this->prepare('LEFT JOIN purchase_order po ON po.`order_id` = o.`order_id`'); + } + if (!empty($filter['refundAmountStart'])) { + $wheres[] = $this->prepare("AND afs.`refund_amount` >= %s", $filter['refundAmountStart']); + } + if (!empty($filter['refundAmountEnd'])) { + $wheres[] = $this->prepare("AND afs.`refund_amount` <= %s", $filter['refundAmountEnd']); + } + if (!empty($filter['purchasePlatform'])) { + $wheres[] = $this->prepare("AND po.`purchase_platform` = %s", $filter['purchasePlatform']); + $joinTables['purchase_order'] = $this->prepare('LEFT JOIN purchase_order po ON po.`order_id` = o.`order_id`'); + } + if (!empty($filter['purchaseOrderSn'])) { + $wheres[] = $this->prepare("AND po.`purchase_order_sn` = %s", $filter['purchaseOrderSn']); + $joinTables['purchase_order'] = $this->prepare('LEFT JOIN purchase_order po ON po.`order_id` = o.`order_id`'); + } + if (!empty($filter['purchaseOrderStatus'])) { + $wheres[] = $this->prepare("AND po.`purchase_order_status` = %s", $filter['purchaseOrderStatus']); + $joinTables['purchase_order'] = $this->prepare('LEFT JOIN purchase_order po ON po.`order_id` = o.`order_id`'); + } + if (!empty($filter['filterPurchaseStatus']) && is_array($filter['filterPurchaseStatus'])) { + $wheres[] = $this->prepare("AND ooe.filter_purchase_status in %li", $filter['filterPurchaseStatus']); + $joinTables[$opOrderExtTbl] = $this->prepare('left join %b ooe on ooe.order_id = o.order_id', $opOrderExtTbl); + } elseif (is_numeric($filter['filterPurchaseStatus'])) { + $wheres[] = $this->prepare("AND ooe.filter_purchase_status = %i", $filter['filterPurchaseStatus']); + $joinTables[$opOrderExtTbl] = $this->prepare('left join %b ooe on ooe.order_id = o.order_id', $opOrderExtTbl); + } + + if (!empty($filter['receiverNameSearchText'])) { + $wheres[] = $this->prepare("AND o.`receiver_name_smd5` = %s", $filter['receiverNameSearchText']); + } + if (!empty($filter['receiverMobileSearchText'])) { + $wheres[] = $this->prepare("AND o.`receiver_phone_smd5` = %s", $filter['receiverMobileSearchText']); + } + + if (isset($filter['speedRefundFlag']) && in_array($filter['speedRefundFlag'], [AfterSalesConst::speedRefundFlagYes, AfterSalesConst::speedRefundFlagNo])) { + $wheres[] = $this->prepare("AND afs.`speed_refund_flag` = %i", $filter['speedRefundFlag']); + } + + if (!empty($joinTables['purchase_order'])) { + $wheres[] = $this->prepare("AND po.`status` = %s", StatusConst::normal); + } + + if (!empty($filter['purchaseOrderBuyer'])) { + $wheres[] = $this->prepare("AND po.status = %s and po.`purchase_order_buyer` = %s", StatusConst::normal, $filter['purchaseOrderBuyer']); + $joinTables[$purchaseOrderTbl] = $this->prepare('LEFT JOIN purchase_order po ON po.`order_id` = o.`order_id`'); + } + + switch ($filter['sortType']) { + case 'applyTimeDesc' : + $orderByString = 'order by afs.recreated_at desc'; + break; + case 'applyTimeAsc' : + $orderByString = 'order by afs.recreated_at asc'; + break; + case 'timeoutTimeDesc' : + $orderByString = 'order by afs.expire_time desc'; + break; + case 'timeoutTimeAsc' : + $orderByString = 'order by afs.expire_time asc'; + break; + } + + return [$wheres, $joinTables, $orderByString]; + } + + public function getAfterSalesCount($mallId, $filter) { + $mallIds = $filter['authMallIds'] ? $filter['authMallIds'] : array($mallId); + + list($conditions, $joinTables) = $this->getSearchCondition($filter, $mallIds); + unset($joinTables[$this->getTable()]); + + $whereStr = !empty($conditions) ? implode(' ', $conditions) : ''; + $joinStr = !empty($joinTables) ? implode(' ', $joinTables) : ''; + + if (count($mallIds) <= 50) { + $count = $this->queryFirstField('select count(*) from %b afs %l where afs.mall_id in %li %l', $this->getTable(), $joinStr, $mallIds, $whereStr); + } else { + $count = 0; + foreach (array_chunk($mallIds, 50) as $chunkMallIds) { + $chunkCount = $this->queryFirstField('select count(*) from %b afs %l where afs.mall_id in %li %l', $this->getTable(), $joinStr, $chunkMallIds, $whereStr); + $count += (int)$chunkCount; + } + } + + return (int)$count; + } + + public function getStatusCountMap($mallIds) { + $rows = $this->query('select after_sales_status, count(*) as after_sales_status_count from %b afs where afs.mall_id in %li and afs.after_sales_status != %i group by afs.`after_sales_status`', $this->getTable(), $mallIds, AfterSalesConst::afterSalesStatusRefundSuccess); + return ZcArrayHelper::mapNameValue($rows, 'after_sales_status', 'after_sales_status_count'); + } } diff --git a/app/libs/daos/Common/LogisticsDao.php b/app/libs/daos/Common/LogisticsDao.php index a5c7444..22cf470 100644 --- a/app/libs/daos/Common/LogisticsDao.php +++ b/app/libs/daos/Common/LogisticsDao.php @@ -2,6 +2,7 @@ namespace Dao\Common; +use CommonTool; use Dao\AbstractDao; use ZcArrayHelper; @@ -20,6 +21,15 @@ class LogisticsDao extends AbstractDao { return $logistics; } + public function getCompanyIdAndNameMap($companyIds, $platform) { + if (CommonTool::anyEmpty($companyIds, $platform)) { + return []; + } + $logisticsPlatformTbl = LogisticsPlatformDao::tableName(); + $rows = $this->query('select lpc.company_id, l.logistics_name from %b l left join %b lpc on lpc.logistics_id = l.logistics_id where lpc.company_id in %li and lpc.platform = %s %l', $this->getTable(), $logisticsPlatformTbl, $companyIds, $platform); + return ZcArrayHelper::mapNameValue($rows, 'companyId', 'logisticsName'); + } + public function getLogisticsMap($status = null, $includeAll = false) { $where = ''; if ($status) { diff --git a/app/libs/daos/Common/LogisticsPlatformDao.php b/app/libs/daos/Common/LogisticsPlatformDao.php index c3b1d0f..873b95c 100644 --- a/app/libs/daos/Common/LogisticsPlatformDao.php +++ b/app/libs/daos/Common/LogisticsPlatformDao.php @@ -20,14 +20,14 @@ class LogisticsPlatformDao extends AbstractDao { } public function getListByLogisticsId($logisticsIds) { - return $this->query('select * from logistics_platform where logistics_id in %li', $logisticsIds); + return $this->query('select * from %b where logistics_id in %li', $this->getTable(), $logisticsIds); } public function getMapByCompanyCodes($companyCodes, $platform) { if (CommonTool::anyEmpty($companyCodes, $platform)) { return []; } - $logistics = $this->query('select l.*,lpc.company_code from logistics_platform lpc left join logistics l on l.logistics_id = lpc.logistics_id where company_code in %ls and platform = %s', $companyCodes, $platform); + $logistics = $this->query('select l.*,lpc.company_code from %b lpc left join logistics l on l.logistics_id = lpc.logistics_id where company_code in %ls and platform = %s', $this->getTable(), $companyCodes, $platform); return ZcArrayHelper::changeKeyRow($logistics, 'companyCode'); } @@ -35,7 +35,15 @@ class LogisticsPlatformDao extends AbstractDao { if (CommonTool::anyEmpty($logisticsIds, $platform)) { return []; } - $rows = $this->query('select logistics_id, company_id from logistics_platform where logistics_id in %li and platform = %s', $logisticsIds, $platform); + $rows = $this->query('select logistics_id, company_id from %b where logistics_id in %li and platform = %s', $this->getTable(), $logisticsIds, $platform); return ZcArrayHelper::mapNameValue($rows, 'logisticsId', 'companyId'); } + + public function getMapByCompanyIds($companyIds, $platform) { + if (CommonTool::anyEmpty($companyIds, $platform)) { + return []; + } + $logistics = $this->query('select l.*,lpc.company_id from %b lpc left join logistics l on l.logistics_id = lpc.logistics_id where company_id in %ls and platform = %s', $this->getTable(), $companyIds, $platform); + return ZcArrayHelper::changeKeyRow($logistics, 'company_id'); + } } diff --git a/app/libs/daos/CustomPrint/CustomOrderExpressNoDao.php b/app/libs/daos/CustomPrint/CustomOrderExpressNoDao.php index c6aa026..1fd97f5 100644 --- a/app/libs/daos/CustomPrint/CustomOrderExpressNoDao.php +++ b/app/libs/daos/CustomPrint/CustomOrderExpressNoDao.php @@ -3,6 +3,7 @@ namespace Dao\CustomPrint; use Dao\AbstractDao; +use OrderPrintConst; class CustomOrderExpressNoDao extends AbstractDao { public function getCustomOrderIdAndExpressNoListMap($mallIds, $customOrderIds) { @@ -15,4 +16,84 @@ class CustomOrderExpressNoDao extends AbstractDao { } return $datas; } + + public function searchPage($mallId, $filter, $page, $pageSize) { + $mallIds = empty($filter['authMallIds']) ? [$mallId] : (is_array($filter['authMallIds']) ? $filter['authMallIds'] : [$filter['authMallIds']]); + list($conditons, $joinTables) = $this->buildSearchLogisticsWarningCustomOrderCondition($filter, $mallId); + $whereStr = !empty($conditons) ? implode(' ', $conditons) : ''; + $joinStr = !empty($joinTables) ? implode(' ', $joinTables) : ''; + return $this->queryPage("SELECT co.* FROM custom_order_express_no coen left join custom_order co on coen.custom_order_id = co.custom_order_id %l WHERE co.mall_id IN %li %l order by coen.`gmt_create` desc", $joinStr, $mallIds, $whereStr, $page, $pageSize); + } + + protected function buildSearchLogisticsWarningCustomOrderCondition($filter, $mallId) { + if (!empty($filter['bizOrderNum'])) { + $whereConditions[] = $this->prepare("AND co.`biz_order_num` = %s", $filter['bizOrderNum']); + unset($filter['orderStartTime'], $filter['orderEndTime']); + } + + if (!empty($filter['orderStartTime'])) { + $whereConditions[] = $this->prepare("AND coen.`gmt_create` >= %s", $filter['orderStartTime']); + } + + if (!empty($filter['orderEndTime'])) { + $whereConditions[] = $this->prepare("AND coen.`gmt_create` <= %s", $filter['orderEndTime']); + } + + if (!empty($filter['waybillCode'])) { + $whereConditions[] = $this->prepare("AND coen.`express_no` = %s", $filter['waybillCode']); + } + + if (!empty($filter['logisticsId'])) { + $whereConditions[] = $this->prepare("AND coen.`logistics_id` = %i", $filter['logisticsId']); + } + + if (!empty($filter['waybillType'])) { + $whereConditions[] = $this->prepare("AND coen.`waybill_type` = %i", $filter['waybillType']); + } + + if ($filter['logisticsStatus']) { + if (is_array($filter['logisticsStatus'])) { + $logisticsStatusWhere = $this->prepare('AND coe.`logistics_status` in %ls', $filter['logisticsStatus']); + } else if ($filter['logisticsStatus'] == OrderPrintConst::logisticsStatusFilterGot) { + $logisticsStatusWhere = $this->prepare('AND coe.`logistics_status` = %s', OrderPrintConst::logisticsActionGot); + } else if ($filter['logisticsStatus'] == OrderPrintConst::logisticsStatusFilterWaitGot) { + $logisticsStatusWhere = $this->prepare('AND coe.`logistics_status` is null'); + } else if ($filter['logisticsStatus'] == OrderPrintConst::logisticsStatusFilterHasTrace) { + $logisticsStatusWhere = $this->prepare('AND coe.`logistics_status` is not null'); + } + + if ($logisticsStatusWhere) { + $whereConditions[] = $logisticsStatusWhere; + $joinTables['custom_order_ext'] = $this->prepare('LEFT JOIN custom_order_ext coe ON co.`custom_order_id` = coe.`custom_order_id`'); + } + } + + if ($filter['logisticsOvertimeType']) { + $filterLogisticsOvertimeType = is_array($filter['logisticsOvertimeType']) ? $filter['logisticsOvertimeType'] : [$filter['logisticsOvertimeType']]; + $whereConditions[] = $this->prepare('AND coe.`logistics_overtime_type` in %li', $filterLogisticsOvertimeType); + $joinTables['custom_order_ext'] = $this->prepare('LEFT JOIN custom_order_ext coe ON co.`custom_order_id` = coe.`custom_order_id`'); + } + + if ($filter['logisticsExceptionOvertimeType']) { + $filterLogisticsOvertimeType = is_array($filter['logisticsExceptionOvertimeType']) ? $filter['logisticsExceptionOvertimeType'] : [$filter['logisticsExceptionOvertimeType']]; + $whereConditions[] = $this->prepare('AND coe.`logistics_exception_overtime_type` in %li', $filterLogisticsOvertimeType); + $joinTables['custom_order_ext'] = $this->prepare('LEFT JOIN custom_order_ext coe ON co.`custom_order_id` = coe.`custom_order_id`'); + } + + if ($filter['notLogisticsWarningAndException']) { + $whereConditions[] = $this->prepare('AND coe.`logistics_overtime_type` is null and coe.`logistics_exception_overtime_type` is null'); + $joinTables['custom_order_ext'] = $this->prepare('LEFT JOIN custom_order_ext coe ON co.`custom_order_id` = coe.`custom_order_id`'); + } + + return [$whereConditions, $joinTables]; + } + + public function getCustomOrderCount($mallId, $filter) { + list($conditions, $joinTables) = $this->buildSearchLogisticsWarningCustomOrderCondition($filter, $mallId); + $whereStr = !empty($conditions) ? implode(' ', $conditions) : ''; + $joinStr = !empty($joinTables) ? implode(' ', $joinTables) : ''; + + $count = $this->queryFirstField("SELECT count(*) FROM custom_order_express_no coen left join custom_order co on coen.custom_order_id = co.custom_order_id %l WHERE co.mall_id = %i %l", $joinStr, $mallId, $whereStr); + return (int)$count; + } } \ No newline at end of file diff --git a/app/libs/daos/CustomPrint/CustomOrderExtDao.php b/app/libs/daos/CustomPrint/CustomOrderExtDao.php index 8da1023..9e66bbb 100644 --- a/app/libs/daos/CustomPrint/CustomOrderExtDao.php +++ b/app/libs/daos/CustomPrint/CustomOrderExtDao.php @@ -3,6 +3,29 @@ namespace Dao\CustomPrint; use Dao\AbstractDao; +use ZcArrayHelper; class CustomOrderExtDao extends AbstractDao { + public function getMapByOrderIds($customOrderIds) { + if (empty($customOrderIds)) { + return []; + } + $rows = $this->query("select * from %b where custom_order_id in %li", $this->getTable(), $customOrderIds); + + if (empty($rows)) { + return []; + } + return ZcArrayHelper::changeKeyRow($rows, 'customOrderId'); + } + + public function batchCancelLogisticsWarning($customOrderIds) { + if (empty($customOrderIds)) { + return false; + } + $updateData = [ + 'logistics_status' => null, + 'logistics_overtime_type' => null, + ]; + return $this->update($updateData, 'custom_order_id IN %li', $customOrderIds); + } } \ No newline at end of file diff --git a/app/libs/daos/FulfillmentOrder/FulfillmentOrderCollectLogDao.php b/app/libs/daos/FulfillmentOrder/FulfillmentOrderCollectLogDao.php new file mode 100644 index 0000000..7dffafb --- /dev/null +++ b/app/libs/daos/FulfillmentOrder/FulfillmentOrderCollectLogDao.php @@ -0,0 +1,11 @@ +queryFirstRow('select * from %b where fulfillment_order_id = %i', $this->getTable(), $fulfillmentOrderId); + } +} \ No newline at end of file diff --git a/app/libs/daos/FulfillmentOrder/FulfillmentOrderDao.php b/app/libs/daos/FulfillmentOrder/FulfillmentOrderDao.php new file mode 100644 index 0000000..d82c0e2 --- /dev/null +++ b/app/libs/daos/FulfillmentOrder/FulfillmentOrderDao.php @@ -0,0 +1,116 @@ +getSearchOrderCondition($filter, $mallIds); + $whereStr = !empty($whereArr) ? implode(' ', $whereArr) : ''; + $joinStr = !empty($joinTables) ? implode(' ', $joinTables) : ''; + + $orderByQuery = $this->getOrderByQueryString($filter['sortType']); + return $this->queryPage("SELECT fo.* FROM %b fo %l WHERE fo.mall_id in %li %l %l", $this->getTable(), $joinStr, $mallIds, $whereStr, $orderByQuery, $page, $pageSize); + } + + private function getSearchOrderCondition($filter, $mallIds) { + $foeTbl = FulfillmentOrderExtDao::tableName(); + $whereConditions = []; + $joinTables = []; + + if ($filter['fulfillmentStatus']) { + $whereConditions[] = $this->prepare('and fo.fulfillment_status = %i', $filter['fulfillmentStatus']); + } + + if (!empty($filter['fulfillmentSn'])) { + $orderSns = is_array($filter['orderSn']) ? $filter['orderSn'] : array($filter['orderSn']); + $whereConditions[] = $this->prepare('and fo.fulfillment_sn in %ls', $orderSns); + } + + if (!empty($filter['orderStartTime'])) { + $whereConditions[] = $this->prepare('and fo.confirm_time >= %s', $filter['orderStartTime']); + } + + if (!empty($filter['orderEndTime'])) { + $whereConditions[] = $this->prepare('and fo.confirm_time <= %s', $filter['orderEndTime']); + } + + if ($filter['goodsId']) { + $filter['goodsId'] = is_array($filter['goodsId']) ? $filter['goodsId'] : [$filter['goodsId']]; + $whereConditions[] = $this->prepare('and fo.goods_id in %li', $filter['goodsId']); + } + + if ($filter['goodsName']) { + $whereConditions[] = $this->prepare('and fo.goods_name like %ss', $filter['goodsName']); + } + + if ($filter['sellerNote']) { + $whereConditions[] = $this->prepare('and fo.seller_note like %ss', $filter['sellerNote']); + } + + if ($filter['promiseDeliveryTimeFilter']) { + if ($filter['promiseDeliveryTimeFilter'] == FulfillmentOrderConst::promiseDeliverTimeOvertime) { + $whereConditions[] = $this->prepare('and fo.promise_delivery_time < %s', date('Y-m-d H:i:s')); + } elseif (in_array($filter['promiseDeliveryTimeFilter'], [FulfillmentOrderConst::promiseDeliverTimeOneDay, FulfillmentOrderConst::promiseDeliverTimeTwoDay, FulfillmentOrderConst::promiseDeliverTimeThreeDay])) { + $promiseDeliverTime = date('Y-m-d H:i:s', strtotime("+{$filter['promiseDeliveryTimeFilter']} hours")); + $whereConditions[] = $this->prepare('and fo.promise_delivery_time > %s and fo.promise_delivery_time < %s', date('Y-m-d H:i:s'), $promiseDeliverTime); + } + } + + if ($filter['goodsLabelCodePrintFilter'] == FulfillmentOrderConst::goodsLabelCodePrinted) { + $joinTables[$foeTbl] = $this->prepare('left join %b foe on fo.fulfillment_sn = foe.fulfillment_sn', $foeTbl); + $whereConditions[] = $this->prepare('and foe.filter_goods_label_code_printed = 1'); + } elseif ($filter['goodsLabelCodePrintFilter'] == FulfillmentOrderConst::goodsLabelCodeNoPrinted) { + $joinTables[$foeTbl] = $this->prepare('left join %b foe on fo.fulfillment_sn = foe.fulfillment_sn', $foeTbl); + $whereConditions[] = $this->prepare('and foe.filter_goods_label_code_printed = 0 or foe.filter_goods_label_code_printed is null'); + } + + return [$whereConditions, $joinTables]; + } + + public function getOrderByQueryString($sortType) { + switch ($sortType) { + case 'orderConfirmTimeDesc': + $query = 'order by fo.`confirm_time` desc'; + break; + case 'orderConfirmTimeAsc': + $query = 'order by fo.`confirm_time` asc'; + break; + case 'promiseDeliveryTimeDesc': + $query = 'order by fo.`promise_delivery_time` desc'; + break; + case 'promiseDeliveryTimeAsc': + $query = 'order by fo.`promise_delivery_time` asc'; + break; + default: + $query = 'order by fo.`confirm_time` desc'; + break; + } + return empty($query) ? '' : $query; + } + + public function getStatusAndOrderCountMap($mallIds) { + $orderStatusAndOrderCountMap = $this->query('select fulfillment_status, count(*) as order_count from %b WHERE mall_id in %li group by fulfillment_status', $this->getTable(), $mallIds); + return ZcArrayHelper::mapNameValue($orderStatusAndOrderCountMap, 'fulfillmentStatus', 'orderCount'); + } + + public function getWillDelaySendOrderCount($mallIds) { + return $this->queryFirstField('select count(*) from %b where mall_id in %li and fulfillment_status = %i and promise_delivery_time > %s and promise_delivery_time < %s', $this->getTable(), $mallIds, FulfillmentOrderConst::fulfillmentOrderStatusWaitSellerSendGoods, date('Y-m-d H:i:s'), date('Y-m-d H:i:s', strtotime("+24 hours"))); + } + + public function getHasDelaySendOrderCount($mallIds) { + return $this->queryFirstField('select count(*) from %b where mall_id in %li and fulfillment_status = %i and promise_delivery_time < %s', $this->getTable(), $mallIds, FulfillmentOrderConst::fulfillmentOrderStatusWaitSellerSendGoods, date('Y-m-d H:i:s')); + } + + public function getCourierCollectOrderCount($mallIds) { + return $this->queryFirstField('select count(*) from %b where mall_id in %li and courier_door_to_door_collect = 1', $this->getTable(), $mallIds); + } + + public function getByFulfillmentSn($fulfillmentSn) { + return $this->queryFirstRow('select * FROM %b WHERE fulfillment_sn = %s', $this->getTable(), $fulfillmentSn); + } +} \ No newline at end of file diff --git a/app/libs/daos/FulfillmentOrder/FulfillmentOrderEncryptDao.php b/app/libs/daos/FulfillmentOrder/FulfillmentOrderEncryptDao.php new file mode 100644 index 0000000..6020387 --- /dev/null +++ b/app/libs/daos/FulfillmentOrder/FulfillmentOrderEncryptDao.php @@ -0,0 +1,9 @@ +queryFirstRow('select * from %b where fulfillment_sn = %s', $this->getTable(), $fulfillmentSn); + } + + public function searchPage($mallId, $filter, $page, $pageSize) { + $mallIds = !empty($filter['authMallIds']) ? (is_array($filter['authMallIds']) ? $filter['authMallIds'] : [$filter['authMallIds']]) : [$mallId]; + $where = $this->getSearchLogWhere($filter); + return $this->queryPage("SELECT * FROM %b WHERE `mall_id` IN %li and is_preview != 1 %l ORDER BY `op_print_goods_label_code_log_id` DESC", $this->getTable(), $mallIds, $where, $page, $pageSize); + } + + private function getSearchLogWhere($filter) { + $whereArray = array(); + if ($filter['startTime']) { + $whereArray[] = $this->prepare('and gmt_create >= %s', $filter['startTime']); + } + if ($filter['endTime']) { + $whereArray[] = $this->prepare('and gmt_create <= %s', $filter['endTime']); + } + if ($filter['fulfillmentSn']) { + $whereArray[] = $this->prepare('and fulfillment_sn in %ls', $filter['fulfillmentSn']); + } + if ($filter['logisticsId']) { + $whereArray[] = $this->prepare('and logistics_id = %s', $filter['logisticsId']); + } + if ($filter['waybillCode']) { + $whereArray[] = $this->prepare('and waybill_code = %s', $filter['waybillCode']); + } + if ($filter['waybillCodes']) { + $whereArray[] = $this->prepare('and express_no in %ls', $filter['waybillCodes']); + } + if($filter['status']) { + $whereArray[] = $this->prepare('and status = %s', $filter['status']); + } + $where = implode(' ', $whereArray); + return $where; + } +} \ No newline at end of file diff --git a/app/libs/daos/FulfillmentOrder/FulfillmentOrderInsensitiveInfoDao.php b/app/libs/daos/FulfillmentOrder/FulfillmentOrderInsensitiveInfoDao.php new file mode 100644 index 0000000..5b84f56 --- /dev/null +++ b/app/libs/daos/FulfillmentOrder/FulfillmentOrderInsensitiveInfoDao.php @@ -0,0 +1,14 @@ +query('select foe.*, foii.receiver_name, foii.receiver_phone, foii.receiver_address from %b foii left join %b foe on foii.fulfillment_order_id = foe.fulfillment_order_id where foii.fulfillment_order_id in %li', $this->getTable(), $encryptTbl, $fulfillmentOrderIds); + return ZcArrayHelper::changeKeyRow($rows, 'fulfillmentOrderId'); + } +} \ No newline at end of file diff --git a/app/libs/daos/FulfillmentOrder/FulfillmentOrderOutstorageHistoryDao.php b/app/libs/daos/FulfillmentOrder/FulfillmentOrderOutstorageHistoryDao.php new file mode 100644 index 0000000..1736d57 --- /dev/null +++ b/app/libs/daos/FulfillmentOrder/FulfillmentOrderOutstorageHistoryDao.php @@ -0,0 +1,40 @@ +getSearchLogWhere($filter); + return $this->queryPage("SELECT * FROM %b WHERE `mall_id` IN %li %l ORDER BY `fulfillment_order_outstorage_history_id` DESC", $this->getTable(), $mallIds, $where, $page, $pageSize); + } + + private function getSearchLogWhere($filter) { + $whereArray = []; + if ($filter['startTime']) { + $whereArray[] = $this->prepare('and gmt_create >= %s', $filter['startTime']); + } + if ($filter['endTime']) { + $whereArray[] = $this->prepare('and gmt_create <= %s', $filter['endTime']); + } + if ($filter['fulfillmentSn']) { + $whereArray[] = $this->prepare('and fulfillment_sn in %ls', $filter['fulfillmentSn']); + } + if ($filter['logisticsId']) { + $whereArray[] = $this->prepare('and logistics_id = %s', $filter['logisticsId']); + } + if ($filter['waybillCode']) { + $whereArray[] = $this->prepare('and waybill_code = %s', $filter['waybillCode']); + } + if ($filter['waybillCodes']) { + $whereArray[] = $this->prepare('and express_no in %ls', $filter['waybillCodes']); + } + if($filter['status']) { + $whereArray[] = $this->prepare('and status = %s', $filter['status']); + } + $where = implode(' ', $whereArray); + return $where; + } +} \ No newline at end of file diff --git a/app/libs/daos/FulfillmentOrder/FulfillmentOrderOutstorageStopDao.php b/app/libs/daos/FulfillmentOrder/FulfillmentOrderOutstorageStopDao.php new file mode 100644 index 0000000..be43f1c --- /dev/null +++ b/app/libs/daos/FulfillmentOrder/FulfillmentOrderOutstorageStopDao.php @@ -0,0 +1,19 @@ +queryFirstRow('select * from %b where mall_id = %i and fulfillment_sn = %s ', $this->getTable(), $mallId, $fulfillmentSn); + } + + public function add($mallId, $fulfillmentSn, $reason) { + return $this->insert(array( + 'mall_id' => $mallId, + 'fulfillment_sn' => $fulfillmentSn, + 'reason' => $reason, + )); + } +} \ No newline at end of file diff --git a/app/libs/daos/FulfillmentOrder/OpPrintGoodsLabelCodeLogDao.php b/app/libs/daos/FulfillmentOrder/OpPrintGoodsLabelCodeLogDao.php new file mode 100644 index 0000000..9413599 --- /dev/null +++ b/app/libs/daos/FulfillmentOrder/OpPrintGoodsLabelCodeLogDao.php @@ -0,0 +1,9 @@ +queryFirstRow('select * from %b where is_default = 1', $this->getTable()); + if (empty($row)) { + return null; + } + $row['globalStyle'] = unserialize($row['globalStyle']); + $row['positionMap'] = unserialize($row['positionMap']); + foreach ($row['positionMap'] as &$item) { + if ($item['nv']['field'] == 'image' || $item['nv']['field'] == 'logo') { + $item['nv']['imgSrc'] = OrderPrintTool::opPubAbsUrl($item['nv']['imgPath']); + } + } + return $row; + } +} \ No newline at end of file diff --git a/app/libs/daos/Order/OpOrderDao.php b/app/libs/daos/Order/OpOrderDao.php index 57cadbb..6eb416b 100644 --- a/app/libs/daos/Order/OpOrderDao.php +++ b/app/libs/daos/Order/OpOrderDao.php @@ -25,7 +25,7 @@ class OpOrderDao extends AbstractDao { if(!empty($filterCondition['sortType'])){ $orderByQuery = $this->getOrderByQuery($filterCondition['sortType']); } - return $this->queryPage("SELECT o.* FROM op_order o %l WHERE o.mall_id in %li %l group by o.`order_id` %l", $joinStr, $filterMallIds, $whereStr, $orderByQuery, $page, $pageSize); + return $this->queryPage("SELECT o.* FROM %b o %l WHERE o.mall_id in %li %l group by o.`order_id` %l", $this->getTable(), $joinStr, $filterMallIds, $whereStr, $orderByQuery, $page, $pageSize); } public function getSearchOrderCondition($filter, $mallIds) { diff --git a/app/libs/daos/Order/OpOrderExtDao.php b/app/libs/daos/Order/OpOrderExtDao.php index 8e80bd2..25bc001 100644 --- a/app/libs/daos/Order/OpOrderExtDao.php +++ b/app/libs/daos/Order/OpOrderExtDao.php @@ -2,8 +2,10 @@ namespace Dao\Order; +use CommonTool; use Dao\AbstractDao; use ZcArrayHelper; +use ZcDbEval; class OpOrderExtDao extends AbstractDao { protected $pk = 'order_id'; @@ -14,4 +16,22 @@ class OpOrderExtDao extends AbstractDao { $opOrderExtData['mall_id'] = $mallId; return $this->insertUpdate($opOrderExtData); } + + public function updateOrderPreOutstorageFlag($mallIds, $orderIds, $isPreOutstorage) { + if (CommonTool::anyEmpty($mallIds, $orderIds)) { + return false; + } + return $this->update('op_order_ext', ['is_pre_outstorage' => $isPreOutstorage ? 1 : 0, 'gmt_modified' => ZcDbEval::now(), 'gmt_pre_outstorage' => ZcDbEval::now()], 'mall_id in %li and order_id in %li', $mallIds, $orderIds); + } + + public function batchCancelLogisticsWarning($orderIds) { + if (empty($orderIds)) { + return false; + } + $updateData = [ + 'logistics_status' => null, + 'logistics_overtime_type' => null, + ]; + return $this->update($updateData, 'order_id IN %li', $orderIds); + } } diff --git a/app/libs/daos/Order/OpOrderLogisticsTraceDao.php b/app/libs/daos/Order/OpOrderLogisticsTraceDao.php new file mode 100644 index 0000000..1b20004 --- /dev/null +++ b/app/libs/daos/Order/OpOrderLogisticsTraceDao.php @@ -0,0 +1,27 @@ +query('select * from %b where logistics_id in %li and tracking_number in %ls order by status_time desc', $this->getTable(), $logisticsIds, $expressNos); + $traceMap = []; + foreach ($list as $trace) { + $traceMap[$trace['logisticsId'].'_'.$trace['trackingNumber']][] = $trace; + } + foreach ($traceMap as &$traceList) { + uasort($traceList, function ($v1, $v2) { + return $v1['statusTime'] < $v2['statusTime']; + }); + } + return $traceMap; + } +} diff --git a/app/libs/daos/Order/OpOrderMapDao.php b/app/libs/daos/Order/OpOrderMapDao.php index 50490c3..797c6c1 100644 --- a/app/libs/daos/Order/OpOrderMapDao.php +++ b/app/libs/daos/Order/OpOrderMapDao.php @@ -4,6 +4,7 @@ namespace Dao\Order; use Dao\AbstractDao; use StatusConst; +use ZcArrayHelper; class OpOrderMapDao extends AbstractDao { public function getListByChildOrderIds($childOrderIds, $status = \StatusConst::normal) { @@ -61,4 +62,38 @@ class OpOrderMapDao extends AbstractDao { public function getExistChildOrderIds( $mallId, $orderIds) { return $this->queryFirstColumn("SELECT child_order_id FROM %b WHERE mall_id = %i AND child_order_id in %li and is_master = 0", $this->getTable(), $mallId, $orderIds); } + + public function getChildOrderIdAndOrderIdMap($childOrderIds) { + $opOrderMap = $this->query('select order_id,child_order_id from %b where child_order_id in %li and status = %s', $this->getTable(), $childOrderIds, StatusConst::normal); + return ZcArrayHelper::mapNameValue($opOrderMap, 'childOrderId', 'orderId'); + } + + public function getOrderIdAndChildOrderIdsMap($orderIds, $status = StatusConst::normal) { + if (empty($orderIds)) { + return []; + } + $opOrderMaps = $this->query('select order_id, child_order_id from %b where order_id in %li and status = %s', $this->getTable(), $orderIds, $status); + $orderIdAndOrderInfoMap = ZcArrayHelper::changeKey($opOrderMaps, 'orderId', true); + $orderIdAndChildOrderIdsMap = array_map(function ($item) { + return ZcArrayHelper::getSub($item, 'childOrderId'); + }, $orderIdAndOrderInfoMap); + + return $orderIdAndChildOrderIdsMap; + } + + public function getParentOrderIdsByChildOrderIds($orderIds, $status = StatusConst::normal) { + if (empty($orderIds)) { + return []; + } + $orderIds = $this->queryFirstColumn('select order_id from %b where child_order_id in %li and status = %s', $this->getTable(), $orderIds, $status); + return array_unique($orderIds); + } + + public function getChildOrderIdsByParentOrderIds($orderIds, $status = StatusConst::normal) { + if (empty($orderIds)) { + return []; + } + $childOrderIds = $this->queryFirstColumn('select child_order_id from %b where order_id in %li and status = %s', $this->getTable(), $orderIds, $status); + return array_unique($childOrderIds); + } } \ No newline at end of file diff --git a/app/libs/daos/OrderPrint/OpOrderExpressNoDao.php b/app/libs/daos/OrderPrint/OpOrderExpressNoDao.php index 4737d8a..7133474 100644 --- a/app/libs/daos/OrderPrint/OpOrderExpressNoDao.php +++ b/app/libs/daos/OrderPrint/OpOrderExpressNoDao.php @@ -10,11 +10,16 @@ class OpOrderExpressNoDao extends AbstractDao { if (empty($orderIds)) { return []; } - $rows = $this->query("select * from op_order_express_no where order_id in %li order by op_order_express_no_id asc", $orderIds); + $rows = $this->query("select * from %b where order_id in %li order by op_order_express_no_id asc", $this->getTable(), $orderIds); return ZcArrayHelper::changeKey($rows, 'orderId', true); } public function getListByLogisticsIdAndWaybillType($mallId, $orderId, $logisticsId, $waybillType) { return $this->query("select * from %b where mall_id = %i and order_id = %i and logistics_id = %i and waybill_type = %i order by op_order_express_no_id asc", $this->getTable(), $mallId, $orderId, $logisticsId, $waybillType); } + + public function getOrderIdAndExpressInfoMap($orderIds) { + $expressList = $this->query('select ooeo.*,oo.order_status, oo.refund_status from op_order_express_no ooeo left join op_order oo on ooeo.order_id = oo.order_id where ooeo.order_id in %li', $orderIds); + return ZcArrayHelper::changeKeyRow($expressList, 'orderId'); + } } diff --git a/app/libs/daos/OrderPrint/OpWaybillInfoDao.php b/app/libs/daos/OrderPrint/OpWaybillInfoDao.php index e889ee5..9e7498e 100644 --- a/app/libs/daos/OrderPrint/OpWaybillInfoDao.php +++ b/app/libs/daos/OrderPrint/OpWaybillInfoDao.php @@ -107,4 +107,8 @@ class OpWaybillInfoDao extends AbstractDao { public function getListByWaybillCodes($waybillCodes) { return $this->query('select * from %b where waybill_code in %ls', $this->getTable(), $waybillCodes); } + + public function getExistsWaybillCodes($waybillCodes) { + return $this->queryFirstColumn('select waybill_code from %b where waybill_code in %ls and wb_user_id > 0', $waybillCodes); + } } \ No newline at end of file diff --git a/app/libs/daos/OrderSend/OpOrderOutstorageHistoryDao.php b/app/libs/daos/OrderSend/OpOrderOutstorageHistoryDao.php index 3a70743..3f352c7 100644 --- a/app/libs/daos/OrderSend/OpOrderOutstorageHistoryDao.php +++ b/app/libs/daos/OrderSend/OpOrderOutstorageHistoryDao.php @@ -79,4 +79,8 @@ class OpOrderOutstorageHistoryDao extends AbstractDao { $data = ZcArrayHelper::filterColumns($data, 'operator_mall_id,source,mall_id,order_sn,purchase_order_sn,purchase_platform,purchase_account,pull_order_count,action,error_code,reason,detail,gmt_create,gmt_modified'); $this->insert($data); } + + public function getLastHistoryIdsByOrderSns($mallIds, $orderSns) { + return $this->queryFirstColumn('SELECT MAX(op_order_outstorage_history_id) FROM %b WHERE mall_id in %li AND order_sn in %ls GROUP BY order_sn', $this->getTable(), $mallIds, $orderSns); + } } diff --git a/app/libs/daos/PendingMatter/PendingMasterQueueDao.php b/app/libs/daos/PendingMatter/PendingMasterQueueDao.php new file mode 100644 index 0000000..dd03db6 --- /dev/null +++ b/app/libs/daos/PendingMatter/PendingMasterQueueDao.php @@ -0,0 +1,9 @@ +queryPage('select * from %b where mall_id = %i order by pending_matter_category_id desc', $this->getTable(), $mallId, $page, $pageSize); + } + + public function getAllByMallId($mallId) { + return $this->query('select * from %b where mall_id = %i order by pending_matter_category_id desc', $this->getTable(), $mallId); + } +} \ No newline at end of file diff --git a/app/libs/daos/PendingMatter/PendingMatterDao.php b/app/libs/daos/PendingMatter/PendingMatterDao.php new file mode 100644 index 0000000..4847622 --- /dev/null +++ b/app/libs/daos/PendingMatter/PendingMatterDao.php @@ -0,0 +1,40 @@ +query('select order_sn, count(*) as pending_matter_count from %b where order_sn IN %ls and status = %s group by order_sn', $this->getTable(), $orderSns, \StatusConst::wait); + return ZcArrayHelper::changeKeyRow($rows, 'orderSn'); + } + + private function getSearchCondition($filter) { + $wheres = []; + if (!empty($filter['orderSn'])) { + $filterOrderSn = is_array($filter['orderSn']) ? $filter['orderSn'] : [$filter['orderSn']]; + $wheres[] = $this->prepare('and pm.order_sn IN %ls', $filterOrderSn); + } + if (isset($filter['pendingMatterCategoryId']) && is_numeric($filter['pendingMatterCategoryId'])) { + $wheres[] = $this->prepare('and pm.pending_matter_category_id = %i', $filter['pendingMatterCategoryId']); + } + if (!empty($filter['status'])) { + $wheres[] = $this->prepare('and pm.status = %s', $filter['status']); + } + return $wheres; + } + + public function searchPage($mallId, $filter, $page, $pageSize) { + $authMallIds = empty($filter['authMallIds']) ? [$mallId] : (is_array($filter['authMallIds']) ? $filter['authMallIds'] : [$filter['authMallIds']]); + + $wheres = $this->getSearchCondition($filter); + $whereString = implode(' ', $wheres); + return $this->queryPage('select pm.* from %b pm where pm.mall_id IN %li %l order by pm.pending_matter_id desc', $this->getTable(), $authMallIds, $whereString, $page, $pageSize); + } +} \ No newline at end of file diff --git a/app/libs/services/AfterSale/AfterSaleService.php b/app/libs/services/AfterSale/AfterSaleService.php index c252e69..a8fefda 100644 --- a/app/libs/services/AfterSale/AfterSaleService.php +++ b/app/libs/services/AfterSale/AfterSaleService.php @@ -2,10 +2,568 @@ namespace Service\AfterSale; +use AfterSalesConst; +use AppConst; +use CommonTool; +use Dao\AfterSale\AfterSalesDao; +use Dao\Common\LogisticsDao; +use Dao\Common\LogisticsPlatformDao; +use Dao\Mall\MallSDao; +use Dao\Order\OpOrderAllergyRefundDao; +use Dao\Order\OpOrderDao; +use Dao\Order\SearchConditionLogDao; +use Exception\BizException; +use OrderPrintConst; +use OrderPrintTool; +use PddApi; +use PermissionTool; +use PurchaseOrderConst; +use Repository\OrderPrint\OrderPrintRepository; use Service\AbstractService; +use ZcArrayHelper; +use ZcDateHelper; class AfterSaleService extends AbstractService { + private $mallSDao; + private $opOrderDao; + private $logisticsDao; + private $logisticsPlatformDao; + private $afterSalesDao; + private $searchConditionLogDao; + private $opOrderAllergyRefundDao; + + private $orderPrintRepository; protected function __construct() { + $this->mallSDao = MallSDao::instance(); + $this->opOrderDao = OpOrderDao::instance(); + $this->logisticsDao = LogisticsDao::instance(); + $this->logisticsPlatformDao = LogisticsPlatformDao::instance(); + $this->afterSalesDao = AfterSalesDao::instance(); + $this->searchConditionLogDao = SearchConditionLogDao::instance(); + $this->opOrderAllergyRefundDao = OpOrderAllergyRefundDao::instance(); + + $this->orderPrintRepository = OrderPrintRepository::instance(); + } + + private function getSearchAfterSalesListFilter($post, $operatorInfo) { + $mallId = $operatorInfo['mallId']; + $filter = []; + $tabType = $post['tabType']; + if (!empty($post['authMallIds'])) { + PermissionTool::checkMultiShopValid($mallId, $post['authMallIds']); + } + if (isset($post['shippingStatus']) && is_numeric($post['shippingStatus'])) { + $filter['shippingStatus'] = $post['shippingStatus']; + } + if (isset($post['afterSalesType']) && is_numeric($post['afterSalesType'])) { + $filter['afterSalesType'] = $post['afterSalesType']; + } + + if (!empty($post['afterSalesStatus'])) { + $filter['afterSalesStatus'] = is_array($post['afterSalesStatus']) ? $post['afterSalesStatus'] : [$post['afterSalesStatus']]; + } + + if (!empty($post['orderSn'])) { + $filter['orderSn'] = CommonTool::convertValToArray($post['orderSn']); + } + if (!empty($post['afterSalesId'])) { + $filter['afterSalesId'] = CommonTool::convertValToArray($post['afterSalesId']); + } + if (!empty($post['goodsId'])) { + $filter['goodsId'] = $post['goodsId']; + } + if (!empty($post['recreatedAtStart'])) { + $filter['recreatedAtStart'] = ZcDateHelper::formatDate($post['recreatedAtStart']); + } + if (!empty($post['recreatedAtEnd'])) { + $filter['recreatedAtEnd'] = date('Y-m-d 23:59:59', strtotime($post['recreatedAtEnd'])); + } + if (!empty($post['purchaseStartTime'])) { + $filter['purchaseStartTime'] = ZcDateHelper::formatDate($post['purchaseStartTime']); + } + if (!empty($post['purchaseEndTime'])) { + $filter['purchaseEndTime'] = date('Y-m-d 23:59:59', strtotime($post['purchaseEndTime'])); + } + if (!empty($post['expireStartTime'])) { + $filter['expireStartTime'] = $post['expireStartTime']; + } + if (!empty($post['expireEndTime'])) { + $filter['expireEndTime'] = $post['expireEndTime']; + } + if (!empty($post['refundAmountStart'])) { + $filter['refundAmountStart'] = $post['refundAmountStart']; + } + if (!empty($post['refundAmountEnd'])) { + $filter['refundAmountEnd'] = $post['refundAmountEnd']; + } + if (!empty($post['purchasePlatform'])) { + $filter['purchasePlatform'] = $post['purchasePlatform']; + } + if (!empty($post['purchaseOrderSn'])) { + $filter['purchaseOrderSn'] = $post['purchaseOrderSn']; + } + if (!empty($post['purchaseOrderStatus'])) { + $filter['purchaseOrderStatus'] = $post['purchaseOrderStatus']; + } + if (isset($post['isPurchase']) && is_numeric($post['isPurchase'])) { + if($post['isPurchase'] == 1){ + $filter['filterPurchaseStatus'] = array(PurchaseOrderConst::filterPurchaseStatusPartPurchase, PurchaseOrderConst::filterPurchaseStatusHasPurchase, PurchaseOrderConst::filterPurchaseStatusManualHasPurchase); + }else{ + $filter['filterPurchaseStatus'] = array(PurchaseOrderConst::filterPurchaseStatusWaitPurchase); + } + } + if (!empty($post['receiverNameOrPhone'])) { + $receiverInfoFilter = []; + if (preg_match('/^[1-9]{1}\d{10}$/', $post['receiverNameOrPhone'])) { + $receiverInfoFilter['receiverPhone'] = $post['receiverNameOrPhone']; + } else { + $receiverInfoFilter['receiverName'] = $post['receiverNameOrPhone']; + } + $kmsSearchList = PddApi::getKmsSearchList($receiverInfoFilter, $operatorInfo['accessToken']); + if (!empty($kmsSearchList['receiverNameSearchText'])) { + $filter['receiverNameSearchText'] = $kmsSearchList['receiverNameSearchText']; + } + if (!empty($kmsSearchList['receiverMobileSearchText'])) { + $filter['receiverMobileSearchText'] = $kmsSearchList['receiverMobileSearchText']; + } + } + + if (isset($post['speedRefundFlag']) && is_numeric($post['speedRefundFlag'])) { + $filter['speedRefundFlag'] = $post['speedRefundFlag']; + } + + if (!empty($post['mallNote'])) { + $filter['mallNote'] = trim($post['mallNote']); + } + + if (isset($post['hasMallNote']) && is_numeric($post['hasMallNote'])) { + $filter['hasMallNote'] = $post['hasMallNote']; + } + + if (!empty($post['mallNoteFlag'])) { + $mallNoteFlag = array_filter($post['mallNoteFlag'], 'is_numeric'); + if ($mallNoteFlag) { + $filter['mallNoteFlag'] = $mallNoteFlag; + } + } + + if (!empty($post['sortType'])) { + $filter['sortType'] = $post['sortType']; + } + + if (!empty($post['purchaseOrderBuyer'])) { + $filter['purchaseOrderBuyer'] = $post['purchaseOrderBuyer']; + } + if (!empty($post['trackingNumber'])) { + $filter['trackingNumbers'] = CommonTool::convertValToArray($post['trackingNumber']); + } + return $filter; + } + + public function searchAfterSalesList($params, $operatorInfo) { + $mallId = $operatorInfo['mallId']; + $page = intval($params['page'] ?: 1); + $pageSize = intval($params['pageSize'] ?: 20); + $filter = $this->getSearchAfterSalesListFilter($params, $operatorInfo); + + $this->searchConditionLogDao->add($mallId, OrderPrintConst::searchConditionBizCodeAfterSale, $params); + + list($afterSalesList, $total, $isSlowQuery) = $this->afterSalesDao->searchPage($mallId, $filter, $page, $pageSize, true); + $mallIds = $filter['authMallIds'] ? $filter['authMallIds'] : array($mallId); + + if ($isSlowQuery) { + throw new BizException('筛选订单数量太多,请减少店铺数量'); + } + $mallIds = $filter['authMallIds'] ? $filter['authMallIds'] : array($mallId); + if (in_array(\Zc::C('appName'), [AppConst::appPddDz, AppConst::appPddDzOp, AppConst::appMsPddOp, AppConst::appMsPddOpEbill])) { + $afterSalesList = $this->getAfterSalesOpOrders($mallIds, $afterSalesList); + } else { + throw new BizException('暂未支持'); + } + + return [ + 'afterSalesList' => $afterSalesList, + 'total' => $total, + ]; + } + + public function getAfterSalesCount($params, $operatorInfo) { + $mallId = $operatorInfo['mallId']; + $mallIds = $params['authMallIds'] ? $params['authMallIds'] : array($mallId); + + $filter = [ + 'authMallIds' => $mallIds, + 'expireStartTime' => date('Y-m-d H:i:s', time()), + 'expireEndTime' => date('Y-m-d H:i:s', strtotime('+ 24 hour')), + ]; + $expireCount = $this->afterSalesDao->getAfterSalesCount($mallId, $filter); + + $afterSalesStatusCountMap = $this->afterSalesDao->getStatusCountMap($mallIds); + + $filter = $this->getSearchAfterSalesListFilter($params, $operatorInfo); + $afterSalesTabAllCount = $this->afterSalesDao->getAfterSalesCount($mallId, $filter); + + $platformAgreeRefundCount = $afterSalesStatusCountMap[AfterSalesConst::afterSalesStatusPlatformAgreeRefund]; + + $afterSalesTabRefundApplyProcessCount = $afterSalesStatusCountMap[AfterSalesConst::afterSalesStatusBuyerApplyRefund] ? : 0; + + $afterSalesTabReturnGoodsProcessCount = $afterSalesStatusCountMap[AfterSalesConst::afterSalesStatusReturnRefund] ? : 0; + + $afterSalesTabExchangeGoodsProcessCount = $afterSalesStatusCountMap[AfterSalesConst::afterSalesStatusExchangeGoodsWaitSellerProcess] ? : 0; + + $afterSalesTabPlatformProcessCount = $afterSalesStatusCountMap[AfterSalesConst::afterSalesStatusPlatformProcessing] ? : 0; + + $afterSalesTabOverdueWithin24HoursCount = $expireCount; + + $filter = [ + 'authMallIds' => $mallIds, + 'afterSalesType' => AfterSalesConst::afterSalesTypeRepair, + ]; + $afterSalesTabMaintainProcessCount = $this->afterSalesDao->getAfterSalesCount($mallId, $filter); + + return [ + 'afterSalesTabAllCount' => $afterSalesTabAllCount, + 'afterSalesTabRefundApplyProcessCount' => $afterSalesTabRefundApplyProcessCount, + 'afterSalesTabReturnGoodsProcessCount' => $afterSalesTabReturnGoodsProcessCount, + 'afterSalesTabExchangeGoodsProcessCount' => $afterSalesTabExchangeGoodsProcessCount, + 'afterSalesTabOverdueWithin24HoursCount' => $afterSalesTabOverdueWithin24HoursCount, + 'afterSalesTabMaintainProcessCount' => $afterSalesTabMaintainProcessCount, + 'afterSalesTabPlatformProcessCount' => $afterSalesTabPlatformProcessCount, + 'expireCount' => $expireCount, + 'platformAgreeRefundCount' => $platformAgreeRefundCount, + ]; + } + + private function getAfterSalesOpOrders($mallIds, $afterSalesList) { + $orderSns = array_unique(ZcArrayHelper::getSub($afterSalesList, 'orderSn')); + $orders = $this->opOrderDao->getListByOrderSns($orderSns); + $orders = $this->orderPrintRepository->rebuildOrderListIfHasOld($orders); + $orders = $this->orderPrintRepository->decryptOrders($orders); + $ordersAndOrderSnMap = ZcArrayHelper::changeKey($orders, 'orderSn'); + $orderIds = array_unique(ZcArrayHelper::getSub($orders, 'orderId')); + + $ordersGoodsList = $this->orderPrintRepository->getOpOrdersGoodsListByOrderIds($orderIds); + $mallIdAndMallNameMap = $this->mallSDao->getMallIdAndMallNameMap($mallIds); + $returnAfterSales = []; + $logisticsIds = array_unique(array_filter(ZcArrayHelper::getSub($orders, 'logisticsId'))); + $pddLogisticsIdAndNameMap = $this->logisticsDao->getCompanyIdAndNameMap($logisticsIds, AppConst::appPlatformPdd); + $allergyRefundOrderIds = $this->opOrderAllergyRefundDao->getOrderIdsByOrderIds($orderIds); + foreach ($afterSalesList as $afterSalesItem) { + $order = $ordersAndOrderSnMap[$afterSalesItem['orderSn']]; + $orderId = $order['orderId']; + $fullAddress = OrderPrintTool::joinFullAddress($order['province'], $order['city'], $order['town'], $order['address']); + $orderGoods = ZcArrayHelper::changeKey($ordersGoodsList[$orderId], 'skuId'); + $orderItems = []; + foreach ($orderGoods as $goods) { + $orderItems[] = array( + 'orderId' => $goods['orderId'], + 'mallId' => $goods['mallId'], + 'goodsId' => $goods['goodsId'], + 'skuId' => $goods['skuId'], + 'skuName' => $goods['skuName'], + 'goodsName' => $goods['goodsName'], + 'goodsPrice' => $goods['goodsPrice'], + 'skuSubName' => $goods['skuSubName'], + 'itemTotal' => $goods['goodsCount'], + 'totalPrice' => $goods['totalPrice'], + 'goodsImg' => $goods['goodsImg'], + 'shortWeight' => $goods['shortWeight'], + 'goodsSpec' => $goods['goodsSpec'], + 'url' => CommonTool::buildPddGoodsUrl($goods['goodsId']), + ); + } + $returnAfterSales[] = [ + 'afterSalesId' => $afterSalesItem['afterSalesId'], + 'orderSn' => $afterSalesItem['orderSn'], + 'speedRefundStatus' => $afterSalesItem['speedRefundStatus'], + 'shippingStatus' => $afterSalesItem['shippingStatus'], + 'afterSalesType' => $afterSalesItem['afterSalesType'], + 'recreatedAt' => $afterSalesItem['recreatedAt'], + 'speedRefundFlag' => $afterSalesItem['speedRefundFlag'], + 'afterSalesStatus' => $afterSalesItem['afterSalesStatus'], + 'refundAmount' => $afterSalesItem['refundAmount'], + 'expireTime' => $afterSalesItem['expireTime'], + 'afterSaleReason' => $afterSalesItem['afterSaleReason'], + 'orderPayment' => $order['payAmount'] + $order['platformDiscount'], + 'receiverName' => $order['receiverName'], + 'receiverPhone' => $order['receiverPhone'], + 'fullAddress' => $fullAddress, + 'mallName' => $mallIdAndMallNameMap[$afterSalesItem['mallId']], + 'orderItems' => $orderItems, + 'orderId' => $orderId, + 'orderStatus' => $order['orderStatus'], + 'refundStatus' => $order['refundStatus'], + 'logisticsName' => $pddLogisticsIdAndNameMap[$order['logisticsId']] ? : '', + 'trackingNumber' => $order['trackingNumber'], + 'confirmTime' => $order['confirmTime'], + 'refundTrackingNumber' => $afterSalesItem['trackingNumber'], + 'refundLogisticsName' => $afterSalesItem['shippingName'], + 'isAllergyRefundOrder' => in_array($orderId, $allergyRefundOrderIds) ? 1 : 0, + ]; + } + + return $returnAfterSales; + } + + private function getOdExportAfterSalesHeaders() { + return [ + '所属店铺', + '退款订单号', + '申请时间', + '客户姓名', + '客户电话', + '客户地址', + '商品标题', + '商品ID', + 'SKUID', + '数量', + '实付金额', + '退款金额', + '售后编号', + '订单状态', + '售后类型', + '售后状态', + '退款原因', + '采购平台', + '采购时间', + '采购账号', + '采购状态', + '采购订单号', + '采购姓名', + '采购电话', + '采购地址', + ]; + } + + private function getOpExportAfterSalesHeaders() { + return [ + '所属店铺', + '订单号', + '申请时间', + '收货人姓名', + '收货人电话', + '收货人地址', + '商品标题', + '商品ID', + 'SKUID', + '数量', + '实付金额', + '退款金额', + '售后编号', + '订单状态', + '订单运单号', + '订单物流公司', + '售后类型', + '售后状态', + '退款原因', + '发货物流信息', + '退货物流信息', + '售后预期时间', + ]; + } + + public function exportAfterSales() { + $pageSize = 20; + $page = 1; + $isOpApp = in_array(Zc::C('appName'), [AppConst::appPddDz, AppConst::appPddDzOp, AppConst::appMsPddOp, AppConst::appMsPddOpEbill]); + + $cookieName = empty($_POST['cookieName']) ? 'exportAfterSales' : $_POST['cookieName']; + $objPHPExcel = new PHPExcel(); + $headers = $isOpApp ? $this->getOpExportAfterSalesHeaders() : $this->getOdExportAfterSalesHeaders(); + + $activeSheet = ExcelTool::createNewSheetAndSetTitle($objPHPExcel, 0, '退款申请单'); + ExcelTool::setSheetRowValues($activeSheet, 1, $headers); + + $mallIds = $_POST['authMallIds'] ? $_POST['authMallIds'] : array($this->mallId); + $filterRet = $this->getSearchAfterSalesListFilter($_POST); + if (CommonTool::isFailRet($filterRet)) { + return $this->renderJSON($filterRet); + } + $filter = $filterRet['filter']; + + $afterSalesList = []; + while (true) { + list($afterSalesChunk, $total) = $this->afterSalesService->searchAfterSalesList($this->mallId, $filter, $page, $pageSize); + + if (!$afterSalesChunk) { + break; + } + + $afterSalesList = array_merge($afterSalesList, $afterSalesChunk); + + if (count($afterSalesChunk) < $pageSize) { + break; + } + + $page ++; + } + + if ($isOpApp) { + $afterSalesList = $this->getAfterSalesOpOrders($mallIds, $afterSalesList); + $this->packOpExportAfterSalesData($activeSheet, $afterSalesList); + } else { + $afterSalesList = $this->getAfterSalesPurchaseOrders($mallIds, $afterSalesList); + $this->packOdExportAfterSalesData($activeSheet, $afterSalesList); + } + + ExcelTool::outputExcel($objPHPExcel, '导出售后单', $cookieName); + exit; + } + + private function packOpExportAfterSalesData(&$activeSheet, $afterSalesList) { + $row = 2; + foreach ($afterSalesList as $afterSales) { + $column = 1; + ExcelTool::setCellValue($activeSheet, $column++, $row, $afterSales['mallName']); + ExcelTool::setCellValue($activeSheet, $column++, $row, $afterSales['orderSn']); + ExcelTool::setCellValue($activeSheet, $column++, $row, $afterSales['recreatedAt']); + ExcelTool::setCellValue($activeSheet, $column++, $row, CommonTool::ensconceString($afterSales['receiverName'], 'name')); + ExcelTool::setCellValue($activeSheet, $column++, $row, CommonTool::ensconceString($afterSales['receiverPhone'], 'mobile')); + ExcelTool::setCellValue($activeSheet, $column++, $row, CommonTool::ensconceString($afterSales['fullAddress'], 'address')); + + foreach ($afterSales['orderItems'] as $orderItem) { + ExcelTool::setCellValue($activeSheet, $column++, $row, $orderItem['skuName']); + ExcelTool::setCellValue($activeSheet, $column++, $row, $orderItem['goodsId']); + ExcelTool::setCellValue($activeSheet, $column++, $row, $orderItem['skuId']); + ExcelTool::setCellValue($activeSheet, $column++, $row, $orderItem['itemTotal']); + } + + ExcelTool::setCellValue($activeSheet, $column++, $row, $afterSales['orderPayment']); + ExcelTool::setCellValue($activeSheet, $column++, $row, $afterSales['refundAmount']); + ExcelTool::setCellValue($activeSheet, $column++, $row, $afterSales['afterSalesId']); + ExcelTool::setCellValue($activeSheet, $column++, $row, OrderConst::getOrderStatusText($afterSales['orderStatus'], $afterSales['refundStatus'])); + ExcelTool::setCellValue($activeSheet, $column++, $row, $afterSales['trackingNumber']); + ExcelTool::setCellValue($activeSheet, $column++, $row, $afterSales['logisticsName']); + ExcelTool::setCellValue($activeSheet, $column++, $row, AfterSalesConst::getAfterSalesTypeMap()[$afterSales['afterSalesType']]); + ExcelTool::setCellValue($activeSheet, $column++, $row, AfterSalesConst::getAfterSalesStatusMap()[$afterSales['afterSalesStatus']]); + ExcelTool::setCellValue($activeSheet, $column++, $row, AfterSalesConst::getAfterSalesTypeMap()[$afterSales['afterSaleReason']]); + ExcelTool::setCellValue($activeSheet, $column++, $row, $afterSales['trackingNumber']); + ExcelTool::setCellValue($activeSheet, $column++, $row, $afterSales['refundTrackingNumber']); + + if (!empty($afterSales['expireTime'])) { + $exireTime = strtotime($afterSales['expireTime']); + if ($exireTime > time()) { + $leftTime = $exireTime - time(); + $leftDays = floor($leftTime / (3600 * 24)); + $leftHours = floor(($leftTime % (3600 * 24)) / 3600); + $leftMinutes = floor((($leftTime % (3600 * 24)) % 3600) / 60); + $timeTip = '距逾期时间还剩'; + if ($leftDays || $leftHours || $leftMinutes) { + $leftDays = $leftDays ? $leftDays . '天' : ''; + $leftHours = $leftHours ? $leftHours . '时' : ''; + $leftMinutes = $leftMinutes ? $leftMinutes . '分' : ''; + $timeTip = $leftDays . $leftHours . $leftMinutes; + } + } else { + $timeTip = '已逾期'; + } + ExcelTool::setCellValue($activeSheet, $column++, $row, $timeTip); + } + + + $row ++; + } + } + + private function packOdExportAfterSalesData(&$activeSheet, $afterSalesList) { + $row = 2; + foreach ($afterSalesList as $afterSales) { + $column = 1; + ExcelTool::setCellValue($activeSheet, $column++, $row, $afterSales['mallName']); + ExcelTool::setCellValue($activeSheet, $column++, $row, $afterSales['orderSn']); + ExcelTool::setCellValue($activeSheet, $column++, $row, $afterSales['recreatedAt']); + ExcelTool::setCellValue($activeSheet, $column++, $row, CommonTool::ensconceString($afterSales['receiverName'], 'name')); + ExcelTool::setCellValue($activeSheet, $column++, $row, CommonTool::ensconceString($afterSales['receiverPhone'], 'mobile')); + ExcelTool::setCellValue($activeSheet, $column++, $row, CommonTool::ensconceString($afterSales['fullAddress'], 'address')); + + foreach ($afterSales['orderItems'] as $orderItem) { + ExcelTool::setCellValue($activeSheet, $column++, $row, $orderItem['skuName']); + ExcelTool::setCellValue($activeSheet, $column++, $row, $orderItem['goodsId']); + ExcelTool::setCellValue($activeSheet, $column++, $row, $orderItem['skuId']); + ExcelTool::setCellValue($activeSheet, $column++, $row, $orderItem['itemTotal']); + } + ExcelTool::setCellValue($activeSheet, $column++, $row, $afterSales['orderPayment']); + ExcelTool::setCellValue($activeSheet, $column++, $row, $afterSales['refundAmount']); + ExcelTool::setCellValue($activeSheet, $column++, $row, $afterSales['afterSalesId']); + ExcelTool::setCellValue($activeSheet, $column++, $row, AfterSalesConst::getShippingStatusMap()[$afterSales['shippingStatus']]); + ExcelTool::setCellValue($activeSheet, $column++, $row, AfterSalesConst::getAfterSalesTypeMap()[$afterSales['afterSalesType']]); + ExcelTool::setCellValue($activeSheet, $column++, $row, AfterSalesConst::getAfterSalesStatusMap()[$afterSales['afterSalesStatus']]); + ExcelTool::setCellValue($activeSheet, $column++, $row, $afterSales['afterSaleReason']); + + foreach ($afterSales['purchaseOrders'] as $purchaseOrder) { + $platformName = PurchaseOrderConst::getPurchasePlatformName($purchaseOrder['purchasePlatform']); + $purchaseOrderStatus = ''; + + if ($purchaseOrder['purchaseOrderStatus'] == PurchaseOrderConst::purchaseOrderStatusHasSend) { + $purchaseOrderStatus = $platformName . '已发货'; + } elseif ($purchaseOrder['purchaseOrderStatus'] == PurchaseOrderConst::purchaseOrderStatusFinished) { + $purchaseOrderStatus = $platformName . '已完成'; + } elseif ($purchaseOrder['purchaseOrderStatus'] == PurchaseOrderConst::purchaseOrderStatusCancel) { + $purchaseOrderStatus = $platformName . '已关闭'; + } elseif ($purchaseOrder['purchaseOrderStatus'] == PurchaseOrderConst::purchaseOrderStatusRefund) { + $purchaseOrderStatus = $platformName . '退款中'; + } else { + $purchaseOrderStatus = $platformName . '未发货'; + } + + ExcelTool::setCellValue($activeSheet, $column++, $row, $purchaseOrder['purchasePlatform']); + ExcelTool::setCellValue($activeSheet, $column++, $row, $purchaseOrder['purchaseOrderStartTime']); + ExcelTool::setCellValue($activeSheet, $column++, $row, $purchaseOrder['purchaseOrderBuyer']); + ExcelTool::setCellValue($activeSheet, $column++, $row, $purchaseOrderStatus); + ExcelTool::setCellValue($activeSheet, $column++, $row, $purchaseOrder['purchaseOrderSn']); + ExcelTool::setCellValue($activeSheet, $column++, $row, $purchaseOrder['purchaseOrderFullname']); + ExcelTool::setCellValue($activeSheet, $column++, $row, $purchaseOrder['purchaseOrderMobile']); + ExcelTool::setCellValue($activeSheet, $column++, $row, $purchaseOrder['purchaseOrderFullAddress']); + } + + $row ++; + } + } + + public function saveDefaultAdditionalAfterSalesColumns() { + $subAccountId = $_SESSION[SessionConst::mallSubAccountId]; + $ret = $this->orderPrintService->saveUserDefaultAdditionalAfterSalesColumns($this->mallId, $subAccountId, $_POST['fields']); + if (!$ret) { + return $this->renderJSON(CommonTool::failResult('保存默认展示字段失败')); + } + return $this->renderJSON(CommonTool::successResult()); + } + + public function triggerRsyncAfterSales() { + $multiShopOptions = $this->mallService->getMultiShopOptions($this->mallId, $_SESSION[SessionConst::mallName], $_SESSION[SessionConst::mallSubAccountId]); + foreach ($multiShopOptions as $authMallId => $shopName) { + $this->opOrderService->tryRsyncAfterSales($authMallId); + } + return $this->renderJSON(CommonTool::successResult()); + } + + public function checkRsyncAfterSalesFinish() { + $multiShopOptions = $this->mallService->getMultiShopOptions($this->mallId, $_SESSION[SessionConst::mallName], $_SESSION[SessionConst::mallSubAccountId]); + $authMallIds = array_keys($multiShopOptions); + $queueCount = $this->afterSalesService->getAfterSalesRsyncQueueCount($authMallIds); + $ret = CommonTool::successResult([ + 'status' => $queueCount ? StatusConst::process : StatusConst::finish + ]); + return $this->renderJSON($ret); + } + + public function updateAfterSaleMallNote() { + $afterSalesId = $_POST['afterSalesId'] ?: null; + $flag = $_POST['flag'] ?: 0; + $mallNote = $_POST['mallNote'] ?: ''; + $afterSalesInfo = $this->afterSalesService->getAfterSalesInfoByAfterSalesId($afterSalesId); + if (strlen($mallNote) > 200) { + return $this->renderJSON(CommonTool::failResult('备注信息不能超过200个字符')); + } + if (empty($afterSalesInfo)) { + return $this->renderJSON(CommonTool::failResult('售后不存在')); + } + $checkRet = $this->mallUtil->checkMultiShopValid($this->mallId, array($afterSalesInfo['mall_id'])); + if (CommonTool::isFailRet($checkRet)) { + return $this->renderJSON($checkRet); + } + $ret = $this->afterSalesService->updateAfterSaleMallNote($afterSalesId, $flag, $mallNote); + return $this->renderJSON($ret); } } \ No newline at end of file diff --git a/app/libs/services/FulfillmentOrder/FulfillmentOrderService.php b/app/libs/services/FulfillmentOrder/FulfillmentOrderService.php new file mode 100644 index 0000000..47f83fd --- /dev/null +++ b/app/libs/services/FulfillmentOrder/FulfillmentOrderService.php @@ -0,0 +1,553 @@ +mallSDao = MallSDao::instance(); + $this->fulfillmentOrderDao = FulfillmentOrderDao::instance(); + $this->fulfillmentOrderExtDao = FulfillmentOrderExtDao::instance(); + $this->fulfillmentOrderInsensitiveInfoDao = FulfillmentOrderInsensitiveInfoDao::instance(); + $this->logisticsDao = LogisticsDao::instance(); + $this->logisticsPlatformDao = LogisticsPlatformDao::instance(); + $this->fulfillmentOrderOutstorageStopDao = FulfillmentOrderOutstorageStopDao::instance(); + $this->fulfillmentOrderOutstorageHistoryDao = FulfillmentOrderOutstorageHistoryDao::instance(); + $this->fulfillmentOrderCollectLogDao = FulfillmentOrderCollectLogDao::instance(); + $this->fulfillmentOrderGoodsLabelCodeDao = FulfillmentOrderGoodsLabelCodeDao::instance(); + $this->opSysFulfillmentGoodsLabelCodeTplDao = OpSysFulfillmentGoodsLabelCodeTplDao::instance(); + $this->opPrintGoodsLabelCodeLogDao = OpPrintGoodsLabelCodeLogDao::instance(); + + $this->mallRepository = MallRepository::instance(); + } + + public function searchOrderList($mallId, $params) { + $page = intval($params['page'] ?: 1); + $pageSize = intval($params['pageSize'] ?: 20); + $filter = $this->getSearchOrderFilter($mallId, $params); + list($orderList, $total) = $this->fulfillmentOrderDao->searchPage($mallId, $filter, $page, $pageSize); + if (empty($orderList)) { + return [ + 'orderList' => $orderList, + 'total' => $total, + ]; + } + + $mallIds = $filter['authMallIds'] ? $filter['authMallIds'] : array($mallId); + $fulfillmentOrderIds = ZcArrayHelper::getSub($orderList, 'fulfillmentOrderId'); + $fulfillmentOrderIdAndReceiverInfoMap = $this->fulfillmentOrderInsensitiveInfoDao->getFulfillmentOrderIdAndReceiverInfoMap($fulfillmentOrderIds); + + $mallIdAndMallNameMap = $this->mallSDao->getMallIdAndMallNameMap($mallIds); + foreach ($orderList as &$order) { + $receiverInfo = $fulfillmentOrderIdAndReceiverInfoMap[$order['fulfillmentOrderId']]; + $order['mallName'] = $mallIdAndMallNameMap[$order['mallIid']]; + $order['receiverName'] = $receiverInfo['receiverName'] ? : ''; + $order['receiverPhone'] = $receiverInfo['receiverPhone'] ?: ''; + $order['receiverAddress'] = $receiverInfo['receiverAddress'] ?: ''; + $order['realReceiverName'] = $receiverInfo['receiverNameS'] ? CommonTool::decrypt($receiverInfo['receiverNameS']) : ''; + $order['realReceiverPhone'] = $receiverInfo['receiverPhoneS'] ? CommonTool::decrypt($receiverInfo['receiverPhoneS']) : ''; + $order['realReceiverAddress'] = $receiverInfo['receiverAddressS'] ? CommonTool::decrypt($receiverInfo['receiverAddressS']) : ''; + } + $orderList = ZcArrayHelper::rebuildArrayKeyToCamelCase($orderList); + return [ + 'orderList' => $orderList, + 'total' => $total, + ]; + } + + private function getSearchOrderFilter($mallId, $params) { + $filter = []; + + $params['authMallIds'] = empty($params['authMallIds']) ? array($mallId) : (is_array($params['authMallIds']) ? $params['authMallIds'] : explode(',', $params['authMallIds'])); + PermissionTool::checkMultiShopValid($mallId, $params['authMallIds']); + + $filter['authMallIds'] = $params['authMallIds']; + + if ($params['orderTab'] == FulfillmentOrderConst::orderTabWaitSend) { + $filter['fulfillmentStatus'] = FulfillmentOrderConst::fulfillmentOrderStatusWaitSellerSendGoods; + } elseif ($params['orderTab'] == FulfillmentOrderConst::orderTabHasSend) { + $filter['fulfillmentStatus'] = FulfillmentOrderConst::fulfillmentOrderStatusWaitBuyerConfirmGoods; + } elseif ($params['orderTab'] == FulfillmentOrderConst::orderTabFinished) { + $filter['fulfillmentStatus'] = FulfillmentOrderConst::fulfillmentOrderStatusFinished; + } + + + if (!empty($params['fulfillmentSn'])) { + $filter['fulfillmentSn'] = is_array($params['fulfillmentSn']) ? $params['fulfillmentSn'] : CommonTool::splitWithComma($params['fulfillmentSn']); + unset($filter['fulfillmentStatus']); + } + + if (empty($params['orderStartTime'])) { + $params['orderStartTime'] = date('Y-m-d H:i:s', strtotime('-7 days')); + } + + if (!empty($params['orderStartTime'])) { + $filter['orderStartTime'] = ZcDateHelper::formatDate($params['orderStartTime']); + } + if (!empty($params['orderEndTime']) && ($params['orderEndTime'] >= $params['orderStartTime'])) { + if (empty($params['orderFilterDatePickTime'])) { + $filter['orderEndTime'] = date('Y-m-d 23:59:59', strtotime($params['orderEndTime'])); + } else { + $filter['orderEndTime'] = ZcDateHelper::formatDate($params['orderEndTime']); + } + } + + + if (!empty($params['goodsId'])) { + $filter['goodsId'] = is_array($params['goodsId']) ? $params['goodsId'] : CommonTool::splitWithComma($params['goodsId']); + } + + if (!empty($params['goodsName'])) { + $filter['goodsName'] = $params['goodsName']; + } + + if (!empty($params['sellerNote'])) { + $filter['sellerNote'] = trim($params['sellerNote']); + } + + if (!empty($params['sortType'])) { + $filter['sortType'] = trim($params['sortType']); + } + + if ($params['promiseDeliveryTimeFilter']) { + $filter['promiseDeliveryTimeFilter'] = $params['promiseDeliveryTimeFilter']; + } + + if ($params['goodsLabelCodePrintFilter']) { + $filter['goodsLabelCodePrintFilter'] = $params['goodsLabelCodePrintFilter']; + } + + if (!empty($params['delaySendStatus'])) { + if ($params['delaySendStatus'] == FulfillmentOrderConst::willDelaySend) { + $filter['promiseDeliveryTimeFilter'] = FulfillmentOrderConst::promiseDeliverTimeOneDay; + } elseif ($params['delaySendStatus'] == FulfillmentOrderConst::hasDelaySend) { + $filter['promiseDeliveryTimeFilter'] = FulfillmentOrderConst::promiseDeliverTimeOvertime; + } elseif ($params['delaySendStatus'] == FulfillmentOrderConst::courierCollect) { + $filter['courierDoorToDoorCollect'] = 1; + } + } + return $filter; + } + + public function getOrderCountMap($mallId, $params) { + $filter = $this->getSearchOrderFilter($mallId, $params); + $mallIds = $filter['authMallIds'] ? $filter['authMallIds'] : array($mallId); + + $orderStatusAndOrderCountMap = $this->fulfillmentOrderDao->getStatusAndOrderCountMap($mallIds); + $willDelaySendOrderCount = $this->fulfillmentOrderDao->getWillDelaySendOrderCount($mallIds); + $hasDelaySendOrderCount = $this->fulfillmentOrderDao->getHasDelaySendOrderCount($mallIds); + $courierCollectOrderCount = $this->fulfillmentOrderDao->getCourierCollectOrderCount($mallIds); + return [ + 'waitSendOrderCount' => $orderStatusAndOrderCountMap[FulfillmentOrderConst::fulfillmentOrderStatusWaitSellerSendGoods] ?: 0, + 'hasSendOrderCount' => $orderStatusAndOrderCountMap[FulfillmentOrderConst::fulfillmentOrderStatusWaitBuyerConfirmGoods] ?: 0, + 'finishOrderCount' => $orderStatusAndOrderCountMap[FulfillmentOrderConst::fulfillmentOrderStatusFinished] ?: 0, + 'willDelaySendOrderCount' => $willDelaySendOrderCount, + 'hasDelaySendOrderCount' => $hasDelaySendOrderCount, + 'courierCollectOrderCount' => $courierCollectOrderCount, + ]; + } + + public function saveBatchSellerNote($mallId, $params) { + $fulfillmentOrderIds = $params['fulfillmentOrderIds']; + $note = $params['note']; + $coverOriginal = (int)$params['coverOriginal']; + if (empty($fulfillmentOrderIds)) { + throw new CheckClientException('请先选择订单'); + } + if (mb_strlen($note, 'utf-8') > 500) { + throw new CheckClientException('便笺信息不能超过500个字'); + } + $orders = $this->fulfillmentOrderDao->getMapByIds($fulfillmentOrderIds); + $autoMallIds = array_values(array_unique(ZcArrayHelper::getSub($orders, 'mallId'))); + PermissionTool::checkMultiShopValid($mallId, $autoMallIds); + + $errorMap = array(); + $successCount = 0; + foreach ($fulfillmentOrderIds as $fulfillmentOrderId) { + if (!isset($orders[$fulfillmentOrderId])) { + $errorMap[$fulfillmentOrderId] = '订单不存在'; + continue; + } + $order = $orders[$fulfillmentOrderId]; + $orderMallId = $order['mallId']; + $updateNote = $note; + if (!$coverOriginal) { + $updateNote = $order ? ($order['sellerNote'] . $updateNote) : $updateNote; + } + if (mb_strlen($updateNote, 'utf-8') > 500) { + $errorMap[$fulfillmentOrderId] = '便笺信息不能超过500个字'; + continue; + } + $updateRet = $this->updateFulfillmentOrderSellerNote($orderMallId, $fulfillmentOrderId, $updateNote); + if (!$updateRet) { + $errorMap[$fulfillmentOrderId] = '更新失败'; + continue; + } + $successCount ++; + } + return [ + 'successCount' => $successCount, + 'errorCount' => count($errorMap), + 'errorMap' => $errorMap, + 'newNote' => $updateNote, + ]; + } + + public function updateFulfillmentOrderSellerNote($mallId, $fulfillmentOrderId, $sellerNote) { + if (empty($mallId) || empty($fulfillmentOrderId)) { + return false; + } + $order = $this->fulfillmentOrderDao->getById($fulfillmentOrderId); + if (!$order || $order['mallId'] != $mallId) { + return false; + } + $update = array( + 'seller_note' => $sellerNote, + ); + $ret = $this->fulfillmentOrderDao->update($update, 'fulfillment_order_id = %i', $fulfillmentOrderId); + return $ret === false ? false : true; + } + + public function getRefundAddressList($mallId, $operatorInfo) { + $operatorMallId = $operatorInfo['mallId']; + if ($operatorMallId == $mallId) { + $accessToken = $operatorInfo['accessToken']; + } else { + $authMalls = PermissionTool::checkMultiShopValid($operatorMallId, [$mallId]); + $accessToken = $authMalls[$mallId]['accessToken']; + } + return PddApi::getRefundAddressList($accessToken); + } + + public function manualOrderOutStorage($mallId, $params) { + $orderId = $params['orderId']; + $logisticsId = $params['logisticsId']; + $expressNo = $params['expressNo']; + $refundAddressId = $params['refundAddressId'] ?: null; + $redeliveryType = $params['isUpdate'] ? FulfillmentOrderConst::orderLogisticsSendRedeliveryTypeModify : FulfillmentOrderConst::orderLogisticsSendRedeliveryTypeFirst; + + $orders = $this->fulfillmentOrderDao->getMapByIds([$orderId]); + $authMallIds = array_values(array_unique(ZcArrayHelper::getSub($orders, 'mallId'))); + + $authMalls = PermissionTool::checkMultiShopValid($mallId, $authMallIds); + + $order = $orders[$orderId]; + $accessToken = $authMalls[$order['mallId']]['accessToken']; + $companyId = $this->logisticsPlatformDao->getCompanyCodeByLogisticsId([$logisticsId], \AppConst::appPlatformPdd); + $deliveryInfo = FulfillmentOrderTool::buildDeliveryInfo($order['fulfillmentSn'], $logisticsId, $companyId, $expressNo, $refundAddressId, $redeliveryType); + $this->logisticsSend($order['mallId'], $mallId, $deliveryInfo, $accessToken, FulfillmentOrderConst::outstorageSourceManual); + } + + public function logisticsSend($mallId, $operatorMallId, $deliveryInfo, $accessToken, $source = '', $needRetry = false) { + if (CommonTool::anyEmpty($mallId, $operatorMallId, $deliveryInfo, $accessToken)) { + throw new CheckClientException('参数错误'); + } + $this->checkLogisticsSend($mallId, $deliveryInfo); + + for ($i = 0; $i < 3; $i++) { + $outstorageRet = PddApi::fulfillmentSend($deliveryInfo, $accessToken); + if (CommonTool::isSuccessRet($outstorageRet)) { + break; + } + $failReason = $outstorageRet['reason']; + if (preg_match('/(商家后台发货|订单已发货|当前发货单不支持发货)/isU', $failReason)) { + $this->fulfillmentOrderOutstorageStopDao->add($mallId, $deliveryInfo['fulfillmentSn'], $failReason); + break; + } + if (!$needRetry) { + break; + } + if (preg_match('/重试/', $failReason)) { + sleep(10); + continue; + } + } + + $this->addFulfillmentOrderOutstorageHistory($mallId, $operatorMallId, $deliveryInfo, $outstorageRet, $source); + if (CommonTool::isSuccessRet($outstorageRet)) { + $this->updateFulfillmentOrderCollectLog($deliveryInfo['fulfillmentSn'], $deliveryInfo['logisticsId'], $deliveryInfo['trackingNumber']); + } else { + throw new BizException($outstorageRet['reason']); + } + } + + private function checkLogisticsSend($mallId, $deliveryInfo) { + if ($deliveryInfo['redeliveryType'] == OrderConst::orderLogisticsSendRedeliveryTypeFirst) { + $fulfillmentSn = $deliveryInfo['fulfillmentSn']; + $orderOutstorageStop = $this->fulfillmentOrderOutstorageStopDao->getByFulfillmentSn($mallId, $fulfillmentSn); + if ($orderOutstorageStop) { + throw new BizException($orderOutstorageStop['reason']); + } + $order = $this->fulfillmentOrderDao->getByFulfillmentSn($fulfillmentSn); + if (in_array($order['fulfillmentStatus'], [FulfillmentOrderConst::fulfillmentOrderStatusWaitBuyerConfirmGoods, FulfillmentOrderConst::fulfillmentOrderStatusFinished])) { + $failReason = $order['fulfillmentStatus'] == FulfillmentOrderConst::fulfillmentOrderStatusWaitBuyerConfirmGoods ? '订单已发货' : '订单已签收'; + $this->fulfillmentOrderOutstorageStopDao->add($mallId, $fulfillmentSn, $failReason); + return CommonTool::failResult($failReason); + throw new BizException($failReason); + } + } + + $logisticsInfo = $this->logisticsPlatformDao->getByCompanyId($deliveryInfo['companyId'], AppConst::appPlatformPdd); + if (empty($logisticsInfo)) { + throw new CheckClientException('发货物流公司未找到'); + } + } + + public function addFulfillmentOrderOutstorageHistory($mallId, $operatorMallId, $deliveryInfo, $outstorageRet, $source = '') { + $status = CommonTool::isSuccessRet($outstorageRet) ? StatusConst::success : StatusConst::fail; + $trans = DbTool::beginTrans(FulfillmentOrderDao::tableName()); + $this->fulfillmentOrderOutstorageHistoryDao->insert(array( + 'mall_id' => $mallId, + 'fulfillment_sn' => $deliveryInfo['fulfillmentSn'], + 'logistics_id' => $deliveryInfo['logisticsId'], + 'company_id' => $deliveryInfo['companyId'], + 'express_no' => $deliveryInfo['trackingNumber'], + 'source' => $source, + 'status' => $status, + 'reason' => $outstorageRet['reason'], + 'detail' => $outstorageRet['detail'], + 'is_cover_old_logistics' => $deliveryInfo['redeliveryType'] == FulfillmentOrderConst::fulfillmentOrderStatusWaitBuyerConfirmGoods ? 1 : 0, + 'operator_mall_id' => $operatorMallId, + 'gmt_outstorage' => \ZcDbEval::now(), + )); + if ($status == \StatusConst::success) { + //更新订单信息 + $update = [ + 'tracking_number' => $deliveryInfo['trackingNumber'], + 'gmt_modified' => \ZcDbEval::now() + ]; + if ($deliveryInfo['redeliveryType'] == FulfillmentOrderConst::orderLogisticsSendRedeliveryTypeFirst) { + $update['fulfillment_status'] = FulfillmentOrderConst::fulfillmentOrderStatusWaitBuyerConfirmGoods; + } + $this->fulfillmentOrderDao->update($update, 'mall_id = %i and order_sn = %s', $mallId, $deliveryInfo['orderSn']); + } + DbTool::commitTrans($trans); + } + + private function updateFulfillmentOrderCollectLog($fulfillmentOrderSn, $logisticsId, $expressNo) { + $order = $this->fulfillmentOrderDao->getByFulfillmentSn($fulfillmentOrderSn); + if (empty($order)) { + return false; + } + $log = $this->fulfillmentOrderCollectLogDao->getByFulfillmentOrderId($order['fulfillmentOrderId']); + if (empty($log)) { + return false; + } + + return $this->fulfillmentOrderCollectLogDao->update([ + 'logistics_id' => $logisticsId, + 'express_no' => $expressNo, + 'shipping_time' => \ZcDbEval::now(), + ], 'fulfillment_order_id = %i', $order['fulfillmentOrderId']); + } + + public function searchOutstorageLog($mallId, $params) { + $page = intval($params['page'] ?: 1); + $pageSize = intval($params['pageSize'] ?: 20); + + $filter = $this->getSearchLogFilter($mallId, $params); + + list($outstorageRows, $total) = $this->fulfillmentOrderOutstorageHistoryDao->searchPage($mallId, $filter, $page, $pageSize); + $outstorageRows = $this->buildUserOutstorageLog($outstorageRows); + return [ + 'outstorageRows' => $outstorageRows, + 'total' => $total, + ]; + } + + public function buildUserOutstorageLog($rows) { + $mallIds = array_column($rows, 'mallId'); + $mallIdAndMallNameMap = $this->mallSDao->getMallIdAndMallNameMap($mallIds); + $logisticsMap = $this->logisticsDao->getLogisticsMap(); + foreach ($rows as &$row) { + $row['mallName'] = $mallIdAndMallNameMap[$row['mallId']]; + $row['logisticsName'] = $logisticsMap[$row['logisticsId']]; + } + return $rows; + } + + private function getSearchLogFilter($mallId, $data) { + $filter = array(); + if ($data['isMultiShop']) { + $data['authMallIds'] = empty($data['authMallIds']) ? array($mallId) : $data['authMallIds']; + PermissionTool::checkMultiShopValid($mallId, $data['authMallIds']); + $filter['authMallIds'] = $data['authMallIds']; + } + $filter['isMultiShop'] = $data['isMultiShop']; + if ($data['logIds']) { + $filter['logIds'] = $data['logIds']; + } + if ($data['startTime']) { + $pattern = '/^([0-9]{4})-([0-9]{2})-([0-9]{2})\s+([0-9]{2})\:([0-9]{2})\:([0-9]{2})$/'; + if (preg_match($pattern, $data['startTime'])) { + $filter['startTime'] = $data['startTime']; + } else { + $filter['startTime'] = date('Y-m-d 00:00:00', strtotime($data['startTime'])); + } + } + if ($data['endTime']) { + $pattern = '/^([0-9]{4})-([0-9]{2})-([0-9]{2})\s+([0-9]{2})\:([0-9]{2})\:([0-9]{2})$/'; + if (preg_match($pattern, $data['endTime'])) { + $filter['endTime'] = $data['endTime']; + } else { + $filter['endTime'] = date('Y-m-d 23:59:59', strtotime($data['endTime'])); + } + } + if ($data['fulfillmentSn']) { + $filter['fulfillmentSn'] = CommonTool::convertValToArray($data['fulfillmentSn']); + } + if ($data['logisticsId']) { + $filter['logisticsId'] = $data['logisticsId']; + } + if ($_POST['waybillCode']) { + $filter['waybillCode'] = CommonTool::convertValToArray($data['waybillCode']); + } + if ($_POST['waybillCodes']) { + $filter['waybillCodes'] = CommonTool::convertValToArray($data['waybillCodes']); + } + + if ($data['status']) { + $filter['status'] = $data['status']; + } + return $filter; + } + + public function getGoodsLabelCodeTplDetail() { + $fulfillmentSn = $_POST['fulfillmentSn']; + $goodsLabelCodeInfo = $this->fulfillmentOrderGoodsLabelCodeDao->getByFulfillmentSn($fulfillmentSn); + if (empty($goodsLabelCodeInfo)) { + throw new BizException('获取商品标签失败'); + } + + $tpl = $this->opSysFulfillmentGoodsLabelCodeTplDao->getDefault(); + if (empty($tpl)) { + throw new BizException('获取商品标签模板失败'); + } + + $tplData = OrderPrintTool::convertTplInfo($tpl); + $goodsLabelCodeInfo = ZcArrayHelper::rebuildArrayKeyToCamelCase($goodsLabelCodeInfo); + $tplData['nodes'] = $this->buildNodePrintText($tplData['nodes'], $goodsLabelCodeInfo); + return [ + 'tplData' => empty($tplData) ? null : $tplData, + 'goodsLabelCodeInfo' => $goodsLabelCodeInfo + ]; + } + + private function buildNodePrintText($nodes, $goodsLabelCodeInfo) { + foreach ($nodes as &$node) { + switch ($node['nv']['field']) { + case LogisticsConst::labelCodeBarcode: + $node['printText'] = $goodsLabelCodeInfo['labelCode']; + break; + case LogisticsConst::bgProdSkcId: + $node['printText'] = $goodsLabelCodeInfo['bgProdSkcId']; + break; + case LogisticsConst::spec: + $node['printText'] = $goodsLabelCodeInfo['spec']; + break; + case LogisticsConst::bgProdSkuId: + $node['printText'] = $goodsLabelCodeInfo['bgProdSkuId']; + break; + case LogisticsConst::madeIn: + $node['printText'] = $goodsLabelCodeInfo['madeIn']; + break; + case LogisticsConst::clothesSpec: + $node['printText'] = $goodsLabelCodeInfo['clothesSpec']; + break; + } + } + + return $nodes; + + } + + public function updateGoodsLabelCodePrintStatus($operateMallId, $params) { + $fulfillmentSn = $params['fulfillmentSn']; + $printRet = $params['printRet']; + $isPreview = $params['isPreview'] ? 1 : 0; + $printStatus = CommonTool::isFailRet($printRet) ? StatusConst::fail : StatusConst::success; + $printReason = isset($printRet['reason']) ? $printRet['reason'] : null; + $fulfillmentOrderInfo = $this->fulfillmentOrderDao->getByFulfillmentSn($fulfillmentSn); + $trans = DbTool::beginTrans(FulfillmentOrderExtDao::instance()); + $insertDto = [ + 'mall_id' => $fulfillmentOrderInfo['mallId'], + 'fulfillment_sn' => $fulfillmentOrderInfo['fulfillmentSn'], + 'operator_mall_id' => $operateMallId, + 'status' => $printStatus, + 'reason' => $printReason, + 'is_preview' => $isPreview, + ]; + + $this->opPrintGoodsLabelCodeLogDao->insert($insertDto); + + $extUpdateDto = [ + 'mall_id' => $fulfillmentOrderInfo['mall_id'], + 'fulfillment_sn' => $fulfillmentOrderInfo['fulfillment_sn'], + 'filter_goods_label_code_printed' => 1, + ]; + $this->fulfillmentOrderExtDao->insertUpdate($extUpdateDto); + DbTool::commitTrans($trans); + } + + public function searchGoodsLabelCodePrintLog($mallId, $params) { + $page = intval($params['page'] ?: 1); + $pageSize = intval($params['pageSize'] ?: 20); + + $filter = $this->getSearchLogFilter($mallId, $params); + + list($goodsLabelCodePrintLogRows, $total) = $this->fulfillmentOrderGoodsLabelCodeDao->searchPage($mallId, $filter, $page, $pageSize); + $goodsLabelCodePrintLogRows = $this->buildGoodsLabelCodePrintLog($goodsLabelCodePrintLogRows); + return [ + 'goodsLabelCodePrintLogRows' => $goodsLabelCodePrintLogRows, + 'total' => $total, + ]; + } + + private function buildGoodsLabelCodePrintLog($rows) { + $rows = $this->mallRepository->appendMallFields($rows); + return $rows; + } +} \ No newline at end of file diff --git a/app/libs/services/Logistics/LogisticsService.php b/app/libs/services/Logistics/LogisticsService.php new file mode 100644 index 0000000..e5f983e --- /dev/null +++ b/app/libs/services/Logistics/LogisticsService.php @@ -0,0 +1,1020 @@ +mallSDao = MallSDao::instance(); + $this->opOrderDao = OpOrderDao::instance(); + $this->pendingMatterDao = PendingMatterDao::instance(); + $this->pendingMatterCategoryDao = PendingMatterCategoryDao::instance(); + $this->pendingMatterBufferDao = PendingMatterBufferDao::instance(); + $this->searchConditionLogDao = SearchConditionLogDao::instance(); + $this->opOrderOutstorageHistoryDao = OpOrderOutstorageHistoryDao::instance(); + $this->opOrderMapDao = OpOrderMapDao::instance(); + $this->opOrderExpressNoDao = OpOrderExpressNoDao::instance(); + $this->opOrderExtDao = OpOrderExtDao::instance(); + $this->opOrderReceiveAddressDao = OpOrderReceiveAddressDao::instance(); + $this->opOrderLogisticsTraceDao = OpOrderLogisticsTraceDao::instance(); + $this->orderPrintRepository = OrderPrintRepository::instance(); + $this->opLogisticsStatusCheckBufferDao = OpLogisticsStatusCheckBufferDao::instance(); + $this->opWaybillInfoDao = OpWaybillInfoDao::instance(); + $this->customOrderExpressNoDao = CustomOrderExpressNoDao::instance(); + $this->customOrderExtDao = CustomOrderExtDao::instance(); + $this->customOrderDao = CustomOrderDao::instance(); + $this->logisticsDao = LogisticsDao::instance(); + $this->logisticsPlatformDao = LogisticsPlatformDao::instance(); + } + + public function getPreOutstorageOrderList($params, $operatorInfo) { + $mallId = $operatorInfo['mallId']; + $page = intval($params['page'] ?: 1); + $pageSize = intval($params['pageSize'] ?: 20); + + $this->searchConditionLogDao->add($mallId, OrderPrintConst::searchConditionBizCodePreOutStorage, $params); + + $params = $this->buildSearchPreOutstorageOrderCondition($params, $operatorInfo); + if ($params['onlyShowRefunding'] && $params['onlyShowRefunded']) { + return [ + 'orderList' => [], + 'total' => 0, + ]; + } + list($orderList, $total) = $this->searchPreOutstorageOrderList($mallId, $params, $page, $pageSize); + + return [ + 'orderList' => $orderList, + 'total' => $total, + ]; + } + + public function searchPreOutstorageOrderList($mallId, $filterCondition, $page, $pageSize) { + $mallIds = !empty($filterCondition['authMallIds']) ? (is_array($filterCondition['authMallIds']) ? $filterCondition['authMallIds'] : [$filterCondition['authMallIds']]) : [$mallId]; + list ($orderList, $total) = $this->opOrderDao->searchPage($mallIds, $filterCondition, $page, $pageSize); + if (empty($orderList)) { + return array(); + } + + $orderIds = ZcArrayHelper::getSub($orderList, 'orderId'); + $childOrderIdAndOrderIdMap = $this->opOrderMapDao->getChildOrderIdAndOrderIdMap($orderIds); + $ordersIdExpressInfosMap = $this->opOrderExpressNoDao->getMapByOrderIds(array_unique(array_merge($orderIds, $childOrderIdAndOrderIdMap))); + $ordersCustomAddr = $this->opOrderReceiveAddressDao->getListByOrderIds($orderIds); + $orderGoodsList = $this->orderPrintRepository->getOpOrdersGoodsListByOrderIds($orderIds); + $orderExts = $this->opOrderExtDao->getMapByIds($orderIds); + $mallIdAndMallNameMap = $this->mallSDao->getMallIdAndMallNameMap($mallIds); + $logisticsIds = $expressNos = []; + foreach ($orderList as $order) { + $orderId = $order['orderId']; + if ($ordersIdExpressInfosMap[$orderId][0]) { + $logisticsIds[] = $ordersIdExpressInfosMap[$orderId][0]['logisticsId']; + $expressNos[] = $ordersIdExpressInfosMap[$orderId][0]['expressNo']; + } + } + + $traceMap = $this->opOrderLogisticsTraceDao->getLogisticsAndTraceListMap($logisticsIds, $expressNos); + $rows = array(); + $orderList = $this->orderPrintRepository->decryptOrders($orderList); + foreach ($orderList as $order) { + $orderId = $order['orderId']; + $orderMallId = $order['mallId']; + + + $customAddr = $ordersCustomAddr[$orderId]; + $mobile = $customAddr ? CommonTool::ensconceString($customAddr['mobile'], 'mobile') : $order['receiverPhone']; + $telephone = $customAddr ? CommonTool::ensconceString($customAddr['telephone'], 'mobile') : $order['receiverPhone']; + $expressDetail = $ordersIdExpressInfosMap[$orderId][0]; + $traceKey = $expressDetail['logisticsId'] . '_' . $expressDetail['expressNo']; + + $fullName = $customAddr ? CommonTool::ensconceString($customAddr['fullname'], 'webViewName') : $order['receiverName']; + $address = $customAddr ? CommonTool::ensconceString($customAddr['address'], 'webViewAddress') : $order['address']; + $fullAddress = OrderPrintTool::joinFullAddress($order['province'], $order['city'], $order['town'], $address); + + if ($childOrderIdAndOrderIdMap[$orderId]) { + $expressDetail = $ordersIdExpressInfosMap[$childOrderIdAndOrderIdMap[$orderId]][0]; + } + + $rows[$orderId] = array( + 'mallName' => $mallIdAndMallNameMap[$orderMallId], + 'bFullname' => $fullName, + 'bTelephone' => $telephone, + 'bMobile' => $mobile, + 'bFullAddress' => $fullAddress, + 'expressDetail' => $expressDetail, + 'logisticsStatus' => $orderExts[$orderId]['logisticsStatus'], + 'traceList' => $traceMap[$traceKey], + ); + + $order['goodsList'] = $orderGoodsList[$orderId]; + $rows[$orderId] = array_merge($rows[$orderId], OrderPrintTool::formartOrderDetailNv($order)); + + + } + $this->buildPreAutoOutstorageStatusToOpOrder($mallIds, $rows); + + return [$rows, $total]; + } + + public function buildPreAutoOutstorageStatusToOpOrder($mallIds, &$orders) { + if (empty($orders)) { + return false; + } + $orderSns = ZcArrayHelper::getSub($orders, 'orderSn'); + $lastOpOrderOutstorageHistoryIds = $this->opOrderOutstorageHistoryDao->getLastHistoryIdsByOrderSns($mallIds, $orderSns); + $opOrderOutstorageHistoryList = $this->opOrderOutstorageHistoryDao->getListByIds($lastOpOrderOutstorageHistoryIds); + $orderSnAndOutstorageInfoMap = ZcArrayHelper::changeKeyRow($opOrderOutstorageHistoryList, 'ordeSn'); + foreach ($orders as &$order) { + $orderSn = $order['orderSn']; + if (isset($orderSnAndOutstorageInfoMap[$orderSn]) && $orderSnAndOutstorageInfoMap[$orderSn]['source'] == PurchaseOrderConst::outstorageSourcePreAuto) { + $lastHistory = $orderSnAndOutstorageInfoMap[$orderSn]; + $order['preAutoOutstorageStatus'] = $lastHistory['status']; + $order['preAutoOutstorageReason'] = $lastHistory['reason']; + } + } + + } + + protected function buildSearchPreOutstorageOrderCondition($params, $operatorInfo) { + $mallId = $operatorInfo['accessToken']; + $params['orderStatus'] = OrderConst::orderStatusWaitSellerSendGoods; + $params['isPreOutstorage'] = 1; + if (is_numeric($params['isRefund'])) { + if ($params['isRefund']) { + $params['refundStatus'] = [OrderConst::refundStatusProcessing, OrderConst::refundStatusRefunding, OrderConst::refundStatusSuccess]; + } else { + $params['refundStatus'] = OrderConst::refundStatusNoRefund; + } + } + if ($params['delaySendStatus'] == OrderConst::willDelaySend) { + $params['afterSalesLastShipLeftHours'] = 12; + } + + if ($params['orderSn']) { + $params['orderSn'] = trim($params['orderSn']); + } + if ($params['waybillCode']) { + $params['waybillCode'] = trim($params['waybillCode']); + } + if (!empty($params['orderEndTime']) && ($params['orderEndTime'] >= $params['orderStartTime'])) { + $params['orderEndTime'] = date('Y-m-d 23:59:59', strtotime($params['orderEndTime'])); + } + if (!empty($params['authMallIds'])) { + $params['authMallIds'] = empty($params['authMallIds']) ? array($mallId) : $params['authMallIds']; + PermissionTool::checkMultiShopValid($mallId, $params['authMallIds']); + } + if (!empty($data['orderStartTime'])) { + $condition['orderStartTime'] = ZcDateHelper::formatDate($data['orderStartTime']); + } + if (!empty($data['orderEndTime']) && ($data['orderEndTime'] >= $data['orderStartTime'])) { + $condition['orderEndTime'] = date('Y-m-d 23:59:59', strtotime($data['orderEndTime'])); + } + if (isset($params['timeType']) && in_array($params['timeType'], ['createdTime', 'preOutstorageTime'])) { + if (!empty($params['orderStartTime'])) { + if ($params['timeType'] == 'createdTime') { + $params['orderCreatedStartTime'] = ZcDateHelper::formatDate($params['orderStartTime']); + } else { + $params['preOutstorageStartTime'] = ZcDateHelper::formatDate($params['orderStartTime']); + } + } + if (!empty($params['orderEndTime']) && ($params['orderEndTime'] >= $params['orderStartTime'])) { + if ($params['timeType'] == 'createdTime') { + $params['orderCreatedEndTime'] = date('Y-m-d 23:59:59', strtotime($params['orderEndTime'])); + } else { + $params['preOutstorageEndTime'] = date('Y-m-d 23:59:59', strtotime($params['orderEndTime'])); + } + } + unset($params['orderStartTime']); + unset($params['orderEndTime']); + } + if ($params['onlyShowAutoShipFailed']) { + $params['onlyShowAutoShipFailed'] = trim($params['onlyShowAutoShipFailed']); + } + if ($params['onlyShowRefunding']) { + $params['refundStatus'] = [OrderConst::refundStatusProcessing, OrderConst::refundStatusRefunding]; + } + if ($params['onlyShowRefunded']) { + $params['refundStatus'] = OrderConst::refundStatusSuccess; + } + + $kmsSearchList = PddApi::getKmsSearchList($params, $operatorInfo['accessToken']); + if (!empty($kmsSearchList['receiverNameSearchText'])) { + $params['receiverNameSearchText'] = $kmsSearchList['receiverNameSearchText']; + } + if (!empty($kmsSearchList['receiverMobileSearchText'])) { + $params['receiverMobileSearchText'] = $kmsSearchList['receiverMobileSearchText']; + } + + if(isset($params['sortType'])){ + $printOrderSortTypeArray = array_keys(OrderPrintTool::getOpPreOutstorageSortTypeMap()); + $condition['sortType'] = in_array($params['sortType'], $printOrderSortTypeArray) ? $params['sortType'] : $printOrderSortTypeArray[0]; + } + + return $params; + } + + public function orderPreOutstorage($mallId, $orderIds) { + $orderInfos = $this->opOrderDao->getMapByIds($orderIds); + $authMallIds = ZcArrayHelper::getSub($orderInfos, 'mallId'); + PermissionTool::checkMultiShopValid($mallId, $authMallIds); + + return $this->preOutstorageOrders($authMallIds, $orderIds); + } + + private function preOutstorageOrders($mallIds, $orderIds) { + $orderIds = array_unique(array_filter($orderIds)); + + $orderIdAncChildOrderIdsMap = $this->opOrderMapDao->getOrderIdAndChildOrderIdsMap($orderIds); + $singleOrderIds = array_diff($orderIds, array_keys($orderIdAncChildOrderIdsMap)); + foreach ($singleOrderIds as $singleOrderId) { + $orderIdAncChildOrderIdsMap[$singleOrderId] = [$singleOrderId]; + } + + $orderIdAndExpressInfoMap = $this->opOrderExpressNoDao->getOrderIdAndExpressInfoMap(array_keys($orderIdAncChildOrderIdsMap)); + $wxExpressNos = $this->opWaybillInfoDao->getExistsWaybillCodes(array_column($orderIdAndExpressInfoMap, 'expressMo')); + $outstorageExpressNos = []; + + $orderIdErrorMap = []; + $preOutstorageOrderIds = []; + $preOutstorageOrderIdCount = 0; + foreach ($orderIdAncChildOrderIdsMap as $parentOrderId => $childOrderIds) { + $preOutstorageOrderIdCount += count($childOrderIds); + $expressItem = $orderIdAndExpressInfoMap[$parentOrderId]; + if (empty($expressItem)) { + $orderIdErrorMap[] = count($childOrderIds) . '个订单未打印'; + continue; + } + $orderSn = $expressItem['orderSn']; + if (in_array($expressItem['expressNo'], $wxExpressNos)) { + $orderIdErrorMap[$orderSn] = '预发货暂时不支持站外面单'; + continue; + } + if ($expressItem['waybillType'] != LogisticsConst::waybillPdd || $expressItem['express_type'] != OrderPrintConst::expressTypeDzmd) { + $orderIdErrorMap[$orderSn] = '预发货暂时只支持拼多多电子面单'; + continue; + } + if ($expressItem['orderStatus'] != OrderConst::orderStatusWaitSellerSendGoods || $expressItem['refund_status'] != OrderConst::refundStatusNoRefund) { + $orderIdErrorMap[$orderSn] = '订单状态错误'; + continue; + } + $preOutstorageOrderIds = array_merge($preOutstorageOrderIds, $childOrderIds); + $outstorageExpressNos[] = $expressItem['expressNo']; + + } + + $successCount = 0; + if ($preOutstorageOrderIds) { + $preOutstorageOrderIds = array_unique($preOutstorageOrderIds); + $successCount = (int)$this->opOrderExtDao->updateOrderPreOutstorageFlag($mallIds, $preOutstorageOrderIds, 1); + $this->opLogisticsStatusCheckBufferDao->update(['gmt_exec' => ZcDbEval::now(), 'gmt_modified' => ZcDbEval::now()], 'express_no in %ls', $outstorageExpressNos); + } + + return [ + 'totalCount' => $preOutstorageOrderIdCount, + 'successCount' => $successCount, + 'failCount' => $preOutstorageOrderIdCount - $successCount, + 'orderIdErrorMap' => $orderIdErrorMap, + ]; + } + + public function cancelOrderPreOutstorage($mallId, $orderIds) { + if (!is_array($orderIds)) { + $orderIds = [$orderIds]; + } + + $orderInfos = $this->opOrderDao->getListByIds($orderIds); + $authMallIds = ZcArrayHelper::getSub($orderInfos, 'mallId'); + PermissionTool::checkMultiShopValid($mallId, $authMallIds); + + $parentOrderIds = $this->opOrderMapDao->getParentOrderIdsByChildOrderIds($orderIds); + $childOrderIds = $this->opOrderMapDao->getChildOrderIdsByParentOrderIds($parentOrderIds); + + $parentOrderInfos = $this->opOrderDao->getListByIds($parentOrderIds); + foreach ($parentOrderInfos as $parentOrderInfo) { + if ($parentOrderInfo['orderStatus'] != OrderConst::orderStatusWaitSellerSendGoods) { + throw new CheckClientException('父订单不是待发货状态,不允许取消预发货'); + } + } + + $needCancelPreOutstorageOrderIds = array_unique(array_merge($orderIds, $childOrderIds)); + + $affRow = $this->doCancelOrderPreOutstorage($authMallIds, $needCancelPreOutstorageOrderIds); + if ($affRow === false) { + throw new BizException('取消预发货失败'); + } + } + + private function doCancelOrderPreOutstorage($mallIds, $orderIds) { + if (!is_array($orderIds)) { + $orderIds = [$orderIds]; + } + return $this->opOrderExtDao->updateOrderPreOutstorageFlag($mallIds, $orderIds, 0); + } + + public function searchLogisticsWarningOrderList($mallId, $params) { + $page = intval($params['page'] ?: 1); + $pageSize = intval($params['pageSize'] ?: 20); + + $this->searchConditionLogDao->add($mallId, OrderPrintConst::searchConditionBizCodeLogisticsWarning, $params); + + if ($params['orderType'] == 'customOrder') { + list($orderList, $total) = $this->searchLogisticsWarningCustomOrderList($mallId, $params, $page, $pageSize); + } else { + list($orderList, $total) = $this->searchLogisticsWarningPddOrderList($mallId, $params, $page, $pageSize); + } + return [ + 'orderList' => $orderList, + 'total' => $total, + ]; + } + + private function searchLogisticsWarningCustomOrderList($mallId, $params, $page, $pageSize = 20) { + $filterCondition = $this->buildSearchLogisticsWarningCustomOrderCondition($mallId, $params); + list ($orderList, $total) = $this->customOrderExpressNoDao->searchPage($mallId, $filterCondition, $page, $pageSize); + if (empty($orderList)) { + return array([], 0); + } + + $mallIds = array_column($orderList, 'mallId'); + $orderList = ZcArrayHelper::changeKeyRow($orderList, 'customOrderId'); + $customOrderIds = array_keys($orderList); + $orderExpressNos = $this->customOrderExpressNoDao->getCustomOrderIdAndExpressNoListMap($mallIds, $customOrderIds); + $orderExts = $this->customOrderExtDao->getMapByOrderIds($customOrderIds); + + $logisticsIds = $expressNos = []; + foreach ($orderList as $order) { + $orderId = $order['custom_order_id']; + if ($orderExpressNos[$orderId][0]) { + $logisticsIds[] = $orderExpressNos[$orderId][0]['logisticsId']; + $expressNos[] = $orderExpressNos[$orderId][0]['expressNo']; + } + } + $traceMap = $this->opOrderLogisticsTraceDao->getLogisticsAndTraceListMap($logisticsIds, $expressNos); + + $rows = array(); + $orderList = OrderDecryptTool::decryptInfoListByTableName($orderList, 'custom_order'); + $mallIdAndMallNameMap = $this->mallSDao->getMallIdAndMallNameMap($mallIds); + foreach ($orderList as $orderId => $order) { + $expressDetail = $orderExpressNos[$orderId][0]; + $traceKey = $expressDetail['logisticsId'] . '_' . $expressDetail['expressNo']; + $fullAddress = OrderPrintTool::joinFullAddress($order['province'], $order['city'], $order['town'], $order['address']); + + $rows[$orderId] = array( + 'mallName' => $mallIdAndMallNameMap[$order['mallId']], + 'bizOrderNum' => $order['bizOrderNum'], + 'fullname' => $order['receiverName'], + 'telephone' => trim($order['receiverPhone']), + 'mobile' => trim($order['receiverMobile']), + 'fullAddress' => $fullAddress, + 'expressDetail' => $expressDetail, + 'logisticsStatus' => $orderExts[$orderId]['logisticsStatus'], + 'logisticsOvertimeType' => $orderExts[$orderId]['logisticsOvertimeType'], + 'traceList' => $traceMap[$traceKey], + ); + } + return array($rows, $total); + } + + private function buildSearchLogisticsWarningCustomOrderCondition($mallId, $params) { + $params['waybillType'] = LogisticsConst::waybillPdd; + if ($params['overtime'] == OrderPrintConst::logisticsFilterOvertimeGot) { + unset($params['overtime']); + } + + if ($params['overtime'] == OrderPrintConst::logisticsFilterRejection) { + $params['logisticsStatus'] = OrderPrintConst::getLogisticsRejectActions(); + } else if ($params['overtime']) { + $params['logisticsOvertimeType'] = $params['overtime']; + } + unset($params['overtime']); + + $params['bizOrderNum'] = trim($params['orderSn']); + unset($params['orderSn']); + + if ($params['waybillCode']) { + $params['waybillCode'] = trim($params['waybillCode']); + } + + if (!empty($params['orderEndTime']) && ($params['orderEndTime'] >= $params['orderStartTime'])) { + $params['orderEndTime'] = date('Y-m-d 23:59:59', strtotime($params['orderEndTime'])); + } + if ($params['isMultiShop']) { + $params['authMallIds'] = empty($params['authMallIds']) ? array($mallId) : $params['authMallIds']; + PermissionTool::checkMultiShopValid($mallId, $params['authMallIds']); + } + + if (!empty($params['opLogisticsStatus'])) { + if ($params['opLogisticsStatus'] == 'waitGet') { + $params['logisticsStatus'] = OrderPrintConst::logisticsStatusFilterWaitGot; + } elseif ($params['opLogisticsStatus'] == 'onlyGet') { + $params['logisticsStatus'] = [OrderPrintConst::logisticsActionGot]; + } elseif ($params['opLogisticsStatus'] == 'notOnlyGet') { + $params['logisticsStatus'] = [ + OrderPrintConst::logisticsActionArrival, + OrderPrintConst::logisticsActionDeparture, + OrderPrintConst::logisticsActionSend, + OrderPrintConst::logisticsActionFail, + OrderPrintConst::logisticsActionSign, + OrderPrintConst::logisticsActionRejection, + OrderPrintConst::logisticsActionStayInWarehouse, + OrderPrintConst::logisticsActionSignOnBehalf, + OrderPrintConst::logisticsActionOther, + OrderPrintConst::logisticsActionReturn, + OrderPrintConst::logisticsActionInCabinet, + OrderPrintConst::logisticsActionOutCabinet, + OrderPrintConst::logisticsActionClearanceStart, + OrderPrintConst::logisticsActionClearanceFinish, + ]; + } elseif ($params['opLogisticsStatus'] == 'sending') { + $params['logisticsStatus'] = [OrderPrintConst::logisticsActionSend]; + } elseif ($params['opLogisticsStatus'] == 'signed') { + $params['logisticsStatus'] = [ + OrderPrintConst::logisticsActionSign, + OrderPrintConst::logisticsActionSignOnBehalf, + OrderPrintConst::logisticsActionInCabinet, + OrderPrintConst::logisticsActionOutCabinet, + ]; + } + unset($params['opLogisticsStatus']); + } + + if (!empty($params['opWarningStatus'])) { + if ($params['opWarningStatus'] == 'hasWarning') { + $params['logisticsOvertimeType'] = [ + OrderPrintConst::logisticsFilterOvertimeGot, + OrderPrintConst::logisticsFilterOvertimeNoArrival, + OrderPrintConst::logisticsFilterOvertimeNoNewTrace, + OrderPrintConst::logisticsFilterOvertimeNoSign, + OrderPrintConst::logisticsFilterRejection, + OrderPrintConst::logisticsFilterAllocateStay, + OrderPrintConst::logisticsFilterNodeStayJZHW, + OrderPrintConst::logisticsFilterNodeStayJJJ, + OrderPrintConst::logisticsFilterNodeStayTYSF, + OrderPrintConst::logisticsFilterNodeStayBTSF, + OrderPrintConst::logisticsFilterNodeStayXXN, + ]; + } elseif ($params['opWarningStatus'] == 'notGotWarning') { + $params['logisticsOvertimeType'] = [OrderPrintConst::logisticsFilterOvertimeGot]; + } elseif ($params['opWarningStatus'] == 'GotNotUpdateWarning') { + $params['logisticsOvertimeType'] = [OrderPrintConst::logisticsFilterOvertimeNoArrival]; + } elseif ($params['opWarningStatus'] == 'allocateStayWarning') { + $params['logisticsOvertimeType'] = [OrderPrintConst::logisticsFilterAllocateStay]; + } elseif ($params['opWarningStatus'] == 'nodeStayWarning') { + $params['logisticsOvertimeType'] = [ + OrderPrintConst::logisticsFilterNodeStayJZHW, + OrderPrintConst::logisticsFilterNodeStayJJJ, + OrderPrintConst::logisticsFilterNodeStayTYSF, + OrderPrintConst::logisticsFilterNodeStayBTSF, + OrderPrintConst::logisticsFilterNodeStayXXN, + ]; + } elseif ($params['opWarningStatus'] == 'rejectionWarning') { + $params['logisticsOvertimeType'] = [OrderPrintConst::logisticsFilterRejection]; + } elseif ($params['opWarningStatus'] == 'hasException') { + $params['logisticsExceptionOvertimeType'] = [ + OrderPrintConst::logisticsExceptionFilterOvertimeGot, + OrderPrintConst::logisticsExceptionFilterOvertimeNoArrival, + OrderPrintConst::logisticsExceptionFilterAllocateStay, + OrderPrintConst::logisticsExceptionFilterNodeStayJZHW, + OrderPrintConst::logisticsExceptionFilterNodeStayJJJ, + OrderPrintConst::logisticsExceptionFilterNodeStayTYSF, + OrderPrintConst::logisticsExceptionFilterNodeStayBTSF, + OrderPrintConst::logisticsExceptionFilterNodeStayXXN, + ]; + } elseif ($params['opWarningStatus'] == 'notGotException') { + $params['logisticsExceptionOvertimeType'] = [OrderPrintConst::logisticsExceptionFilterOvertimeGot]; + } elseif ($params['opWarningStatus'] == 'GotNotUpdateException') { + $params['logisticsExceptionOvertimeType'] = [OrderPrintConst::logisticsExceptionFilterOvertimeNoArrival]; + } elseif ($params['opWarningStatus'] == 'allocateStayException') { + $params['logisticsExceptionOvertimeType'] = [OrderPrintConst::logisticsExceptionFilterAllocateStay]; + } elseif ($params['opWarningStatus'] == 'nodeStayException') { + $params['logisticsExceptionOvertimeType'] = [ + OrderPrintConst::logisticsExceptionFilterNodeStayJZHW, + OrderPrintConst::logisticsExceptionFilterNodeStayJJJ, + OrderPrintConst::logisticsExceptionFilterNodeStayTYSF, + OrderPrintConst::logisticsExceptionFilterNodeStayBTSF, + OrderPrintConst::logisticsExceptionFilterNodeStayXXN, + ]; + } elseif ($params['opWarningStatus'] == 'normal') { + $params['notLogisticsWarningAndException'] = 1; + } + unset($params['opWarningStatus']); + } + + return $params; + } + + public function searchLogisticsWarningPddOrderList($mallId, $params, $page, $pageSize = 20) { + $filter = $this->buildSearchLogisticsWarningOrderCondition($mallId, $params); + $filter['sortType'] = 'orderStartTimeAsc'; + $mallIds = !empty($filter['authMallIds']) ? (is_array($filter['authMallIds']) ? $filter['authMallIds'] : [$filter['authMallIds']]) : [$mallId]; + list($orderList, $total) = $this->opOrderDao->searchPage($mallIds, $filter, $page, $pageSize); + if (empty($orderList)) { + return [[], 0]; + } + + $orderIds = ZcArrayHelper::getSub($orderList, 'orderId'); + $ordersCustomAddr = $this->opOrderReceiveAddressDao->getListByOrderIds($orderIds); + $orderExts = $this->opOrderExtDao->getMapByIds($orderIds); + $logisticsIds = $expressNos = []; + $pddLogisticsIds = []; + + if ($filter['orderStatus'] == OrderConst::orderStatusWaitSellerSendGoods) { + $ordersExpressNos = $this->opOrderExpressNoDao->getMapByOrderIds($orderIds); + } + + foreach ($orderList as $order) { + $orderId = $order['orderId']; + if ($order['logisticsId']) { + $pddLogisticsIds[] = $order['logisticsId']; + $expressNos[] = $order['trackingNumber']; + } + if ($ordersExpressNos[$orderId][0]) { + $logisticsIds[] = $ordersExpressNos[$orderId][0]['logisticsId']; + $expressNos[] = $ordersExpressNos[$orderId][0]['expressNo']; + } + } + + if ($pddLogisticsIds) { + $companyIdLogisticsMap = $this->logisticsPlatformDao->getMapByCompanyIds($pddLogisticsIds, AppConst::appPlatformPdd); + foreach ($pddLogisticsIds as $logisticsId) { + $logisticsIds[] = $companyIdLogisticsMap[$logisticsId]['logisticsId']; + } + } + + $traceMap = $this->opOrderLogisticsTraceDao->getLogisticsAndTraceListMap($logisticsIds, $expressNos); + + $rows = array(); + $orderList = $this->orderPrintRepository->decryptOrders($orderList); + $mallIdAndMallNameMap = $this->mallSDao->getMallIdAndMallNameMap($mallIds); + foreach ($orderList as $order) { + $orderId = $order['order_id']; + $customAddr = $ordersCustomAddr[$orderId]; + $mobile = $customAddr ? CommonTool::ensconceString($customAddr['mobile'], 'mobile') : $order['receiverPhone']; + $telephone = $customAddr ? CommonTool::ensconceString($customAddr['telephone'], 'mobile') : $order['receiverPhone']; + + $fullName = $customAddr ? CommonTool::ensconceString($customAddr['fullname'], 'webViewName') : $order['receiverName']; + $address = $customAddr ? CommonTool::ensconceString($customAddr['address'], 'webViewAddress') : $order['address']; + $fullAddress = OrderPrintTool::joinFullAddress($order['province'], $order['city'], $order['town'], $address); + + if ($order['logisticsId'] && $order['trackingNumber']) { + $expressDetail = [ + 'logisticsId' => $companyIdLogisticsMap[$order['logisticsId']]['logisticsId'], + 'expressNo' => $order['trackingNumber'], + ]; + } else { + $expressDetail = $ordersExpressNos[$orderId][0]; + } + + $traceKey = $expressDetail['logisticsId'] . '_' . $expressDetail['expressNo']; + + $rows[$orderId] = array( + 'mallName' => $mallIdAndMallNameMap[$order['mallId']], + 'bFullname' => $fullName, + 'bTelephone' => $telephone, + 'bMobile' => $mobile, + 'bFullAddress' => $fullAddress, + 'expressDetail' => $expressDetail, + 'logisticsStatus' => $orderExts[$orderId]['logisticsStatus'], + 'logisticsOvertimeType' => $orderExts[$orderId]['logisticsOvertimeType'], + 'traceList' => $traceMap[$traceKey], + 'refundStatus' => $order['refundStatus'], + 'logisticsExceptionOvertimeType' => $orderExts[$orderId]['logisticsExceptionOvertimeType'], + 'logisticsExceptionOvertimeText' => $orderExts[$orderId]['logisticsExceptionOvertimeText'], + ); + + $rows[$orderId] = array_merge($rows[$orderId], OrderPrintTool::formartOrderDetailNv($order)); + } + return [$rows, $total]; + } + + protected function buildSearchLogisticsWarningOrderCondition($mallId, $params) { + $params['isPrintOrder'] = true; + $params['waybillType'] = LogisticsConst::waybillPdd; + if ($params['waybillCode']) { + $params['waybillCode'] = trim($params['waybillCode']); + } + + if ($params['orderType'] == 'waitSendOrder') { + $params['orderStatus'] = OrderConst::orderStatusWaitSellerSendGoods; + $params['refundStatus'] = OrderConst::refundStatusNoRefund; + if ($params['waybillCode']) { + $params['opWaybillCode'] = $params['waybillCode']; + unset($params['waybillCode']); + } + if ($params['logisticsId']) { + $params['opLogisticsId'] = $params['logisticsId']; + unset($params['logisticsId']); + } + } else { + $params['orderStatus'] = OrderConst::orderStatusWaitBuyerConfirmGoods; + } + + if ($params['overtime'] == OrderPrintConst::logisticsFilterRejection) { + $params['logisticsStatus'] = OrderPrintConst::getLogisticsRejectActions(); + } else if ($params['overtime']) { + $params['logisticsOvertimeType'] = $params['overtime']; + } + unset($params['overtime']); + if (!empty($params['orderEndTime']) && ($params['orderEndTime'] >= $params['orderStartTime'])) { + $params['orderEndTime'] = date('Y-m-d 23:59:59', strtotime($params['orderEndTime'])); + } + if ($params['logisticsId']) { + $params['logisticsId'] = $this->logisticsPlatformDao->getCompanyCodeByLogisticsId($params['logisticsId'], AppConst::appPlatformPdd); + } + if ($params['isMultiShop']) { + $params['authMallIds'] = empty($params['authMallIds']) ? array($mallId) : $params['authMallIds']; + PermissionTool::checkMultiShopValid($mallId, $params['authMallIds']); + } + if (isset($params['timeType'])) { + if ($params['timeType'] == 'createdTime' && !empty($params['orderStartTime'])) { + $params['orderCreatedStartTime'] = ZcDateHelper::formatDate($params['orderStartTime']); + unset($params['orderStartTime']); + } + if ($params['timeType'] == 'createdTime' & !empty($params['orderEndTime']) && ($params['orderEndTime'] >= $params['orderStartTime'])) { + $params['orderCreatedEndTime'] = date('Y-m-d 23:59:59', strtotime($params['orderEndTime'])); + unset($params['orderEndTime']); + } + if ($params['timeType'] == 'orderSendTime' && !empty($params['orderStartTime'])) { + $params['orderSendStartTime'] = ZcDateHelper::formatDate($params['orderStartTime']); + unset($params['orderStartTime']); + } + if ($params['timeType'] == 'orderSendTime' & !empty($params['orderEndTime']) && ($params['orderEndTime'] >= $params['orderStartTime'])) { + $params['orderSendEndTime'] = date('Y-m-d 23:59:59', strtotime($params['orderEndTime'])); + unset($params['orderEndTime']); + } + } + + if (!empty($params['orderRefundStatus'])) { + if ($params['orderRefundStatus'] == 'hasRefund') { + $params['refundStatus'] = [OrderConst::refundStatusProcessing, OrderConst::refundStatusRefunding, OrderConst::refundStatusSuccess]; + } else { + $params['refundStatus'] = OrderConst::refundStatusNoRefund; + } + unset($params['orderRefundStatus']); + } + + if (!empty($params['opLogisticsStatus'])) { + if ($params['opLogisticsStatus'] == 'waitGet') { + $params['logisticsStatus'] = OrderPrintConst::logisticsStatusFilterWaitGot; + } elseif ($params['opLogisticsStatus'] == 'onlyGet') { + $params['logisticsStatus'] = [OrderPrintConst::logisticsActionGot]; + } elseif ($params['opLogisticsStatus'] == 'notOnlyGet') { + $params['logisticsStatus'] = [ + OrderPrintConst::logisticsActionArrival, + OrderPrintConst::logisticsActionDeparture, + OrderPrintConst::logisticsActionSend, + OrderPrintConst::logisticsActionFail, + OrderPrintConst::logisticsActionSign, + OrderPrintConst::logisticsActionRejection, + OrderPrintConst::logisticsActionStayInWarehouse, + OrderPrintConst::logisticsActionSignOnBehalf, + OrderPrintConst::logisticsActionOther, + OrderPrintConst::logisticsActionReturn, + OrderPrintConst::logisticsActionInCabinet, + OrderPrintConst::logisticsActionOutCabinet, + OrderPrintConst::logisticsActionClearanceStart, + OrderPrintConst::logisticsActionClearanceFinish, + ]; + } elseif ($params['opLogisticsStatus'] == 'sending') { + $params['logisticsStatus'] = [OrderPrintConst::logisticsActionSend]; + } elseif ($params['opLogisticsStatus'] == 'signed') { + $params['logisticsStatus'] = [ + OrderPrintConst::logisticsActionSign, + OrderPrintConst::logisticsActionSignOnBehalf, + OrderPrintConst::logisticsActionInCabinet, + OrderPrintConst::logisticsActionOutCabinet, + ]; + } + unset($params['opLogisticsStatus']); + } + + if (!empty($params['opWarningStatus'])) { + if ($params['opWarningStatus'] == 'hasWarning') { + $params['logisticsOvertimeType'] = [ + OrderPrintConst::logisticsFilterOvertimeGot, + OrderPrintConst::logisticsFilterOvertimeNoArrival, + OrderPrintConst::logisticsFilterOvertimeNoNewTrace, + OrderPrintConst::logisticsFilterOvertimeNoSign, + OrderPrintConst::logisticsFilterRejection, + OrderPrintConst::logisticsFilterAllocateStay, + OrderPrintConst::logisticsFilterNodeStayJZHW, + OrderPrintConst::logisticsFilterNodeStayJJJ, + OrderPrintConst::logisticsFilterNodeStayTYSF, + OrderPrintConst::logisticsFilterNodeStayBTSF, + OrderPrintConst::logisticsFilterNodeStayXXN, + ]; + } elseif ($params['opWarningStatus'] == 'notGotWarning') { + $params['logisticsOvertimeType'] = [OrderPrintConst::logisticsFilterOvertimeGot]; + } elseif ($params['opWarningStatus'] == 'GotNotUpdateWarning') { + $params['logisticsOvertimeType'] = [OrderPrintConst::logisticsFilterOvertimeNoArrival]; + } elseif ($params['opWarningStatus'] == 'allocateStayWarning') { + $params['logisticsOvertimeType'] = [OrderPrintConst::logisticsFilterAllocateStay]; + } elseif ($params['opWarningStatus'] == 'nodeStayWarning') { + $params['logisticsOvertimeType'] = [ + OrderPrintConst::logisticsFilterNodeStayJZHW, + OrderPrintConst::logisticsFilterNodeStayJJJ, + OrderPrintConst::logisticsFilterNodeStayTYSF, + OrderPrintConst::logisticsFilterNodeStayBTSF, + OrderPrintConst::logisticsFilterNodeStayXXN, + ]; + } elseif ($params['opWarningStatus'] == 'rejectionWarning') { + $params['logisticsOvertimeType'] = [OrderPrintConst::logisticsFilterRejection]; + } elseif ($params['opWarningStatus'] == 'hasException') { + $params['logisticsExceptionOvertimeType'] = [ + OrderPrintConst::logisticsExceptionFilterOvertimeGot, + OrderPrintConst::logisticsExceptionFilterOvertimeNoArrival, + OrderPrintConst::logisticsExceptionFilterAllocateStay, + OrderPrintConst::logisticsExceptionFilterNodeStayJZHW, + OrderPrintConst::logisticsExceptionFilterNodeStayJJJ, + OrderPrintConst::logisticsExceptionFilterNodeStayTYSF, + OrderPrintConst::logisticsExceptionFilterNodeStayBTSF, + OrderPrintConst::logisticsExceptionFilterNodeStayXXN, + ]; + } elseif ($params['opWarningStatus'] == 'notGotException') { + $params['logisticsExceptionOvertimeType'] = [OrderPrintConst::logisticsExceptionFilterOvertimeGot]; + } elseif ($params['opWarningStatus'] == 'GotNotUpdateException') { + $params['logisticsExceptionOvertimeType'] = [OrderPrintConst::logisticsExceptionFilterOvertimeNoArrival]; + } elseif ($params['opWarningStatus'] == 'allocateStayException') { + $params['logisticsExceptionOvertimeType'] = [OrderPrintConst::logisticsExceptionFilterAllocateStay]; + } elseif ($params['opWarningStatus'] == 'nodeStayException') { + $params['logisticsExceptionOvertimeType'] = [ + OrderPrintConst::logisticsExceptionFilterNodeStayJZHW, + OrderPrintConst::logisticsExceptionFilterNodeStayJJJ, + OrderPrintConst::logisticsExceptionFilterNodeStayTYSF, + OrderPrintConst::logisticsExceptionFilterNodeStayBTSF, + OrderPrintConst::logisticsExceptionFilterNodeStayXXN, + ]; + } elseif ($params['opWarningStatus'] == 'normal') { + $params['notLogisticsWarningAndException'] = 1; + } + unset($params['opWarningStatus']); + } + + return $params; + } + + public function batchUpdateLogisticsTrace($deliveryInfos) { + $logisticsIds = ZcArrayHelper::getSub($deliveryInfos, 'logisticsId'); + $logisticsIdCompanyCodeMap = $this->logisticsPlatformDao->getLogisticsIdAndCompanyIdMap($logisticsIds, AppConst::appPlatformPdd); + + $fCnt = $sCnt = 0; + foreach ($deliveryInfos as $data) { + $expressNo = $data['expressNo']; + $logisticsId = $data['logisticsId']; + $companyCode = $logisticsIdCompanyCodeMap[$logisticsId]; + + try { + $this->updateLogisticsTraceFromPdd($companyCode, $logisticsId, $expressNo); + $sCnt ++; + } catch (Exception $e) { + $fCnt ++; + } + } + + return [ + 'fCnt' => $fCnt, + 'sCnt' => $sCnt + ]; + } + + public function updateLogisticsTraceFromPdd($companyCode, $logisticsId, $expressNo) { + $traceRet = PddApi::getPddLogisticsTrace($companyCode, $expressNo, false); + if (CommonTool::isFailRet($traceRet)) { + throw new BizException($traceRet['reason']); + } + $insertList = []; + foreach ($traceRet['trace_list'] as $item) { + $insertList[] = [ + 'logistics_id' => $logisticsId, + 'tracking_number' => $expressNo, + 'status_desc' => $item['status_desc'], + 'action' => $item['action'], + 'node_description' => $item['node_description'], + 'status_time' => $item['status_time'], + 'time' => $item['time'], + 'desc' => $item['desc'], + ]; + } + + if (empty($insertList)) { + return; + } + $this->opOrderLogisticsTraceDao->delete('logistics_id = %i and tracking_number = %s', $logisticsId, $expressNo); + $this->opOrderLogisticsTraceDao->insert($insertList); + } + + public function batchCancelLogisticsWarning($mallId, $orderIds, $orderType) { + if (!$orderIds) { + throw new CheckClientException('请选择要取消的订单'); + } + $orderIds = is_array($orderIds) ? $orderIds : [$orderIds]; + if ($orderType == 'customOrder') { + $orderList = $this->customOrderDao->getListByBizOrderNums($orderIds); + } else { + $orderList = $this->opOrderDao->getListByIds($orderIds); + } + if (!$orderList) { + throw new CheckClientException('订单不存在'); + } + $mallIds = ZcArrayHelper::getSub($orderList, 'mallId'); + PermissionTool::checkMultiShopValid($mallId, $mallIds); + + if ($orderType == 'customOrder') { + $cancelRet = $this->customOrderExtDao->batchCancelLogisticsWarning(ZcArrayHelper::getSub($orderList, 'customOrderId')); + } else { + $cancelRet = $this->opOrderExtDao->batchCancelLogisticsWarning($orderIds); + } + if ($cancelRet === false) { + throw new BizException('取消失败'); + } + } + + public function exportWarningOrder($mallId, $params) { + $orderType = $params['orderType']; + $pageSize = 50; + $page = 1; + + $objPHPExcel = new \PHPExcel(); + + $activeSheet = ExcelTool::createNewSheetAndSetTitle($objPHPExcel, 0, '物流预警'); + + if ($orderType == 'customOrder') { + $headers = $this->getCustomExportWarningOrderHeaders(); + } else { + $headers = $this->getOpExportWarningOrderHeaders(); + } + ExcelTool::setSheetRowValues($activeSheet, 1, $headers); + + $warningOrderList = []; + while (true) { + if ($orderType == 'customOrder') { + list($orderList, $total) = $this->searchLogisticsWarningCustomOrderList($mallId, $params, $page, $pageSize); + } else { + list($orderList, $total) = $this->searchLogisticsWarningPddOrderList($mallId, $params, $page, $pageSize); + } + + if (!$orderList) { + break; + } + + $warningOrderList = array_merge($warningOrderList, $orderList); + + if (count($orderList) < $pageSize) { + break; + } + + $page ++; + } + + if ($orderType == 'customOrder') { + $this->packExportCustomLogisticsWarningData($activeSheet, $warningOrderList); + } else { + $this->packExportLogisticsWarningData($activeSheet, $warningOrderList); + } + ExcelTool::downloadExcel($objPHPExcel, '导出物流预警单'); + exit; + } + + private function packExportLogisticsWarningData(&$activeSheet, $warningOrderList) { + $logisticsMap = $this->logisticsDao->getLogisticsMap(); + $row = 2; + foreach ($warningOrderList as $warningOrder) { + $column = 1; + ExcelTool::setCellValue($activeSheet, $column++, $row, $warningOrder['mallName']); + ExcelTool::setCellValue($activeSheet, $column++, $row, $logisticsMap[$warningOrder['expressDetail']['logisticsId']]); + ExcelTool::setCellValue($activeSheet, $column++, $row, $warningOrder['expressDetail']['express_no']); + ExcelTool::setCellValue($activeSheet, $column++, $row, HtmlTool::renderLogisticsStatus($warningOrder['logisticsStatus'])); + ExcelTool::setCellValue($activeSheet, $column++, $row, (empty($warningOrder['shippingTime']) || $warningOrder['shippingTime'] == '0000-00-00 00:00:00') ? '--' : $warningOrder['shippingTime']); + ExcelTool::setCellValue($activeSheet, $column++, $row, strip_tags(HtmlTool::buildLogisticsWarningHtml($warningOrder['logisticsOvertimeType'], $warningOrder['logisticsStatus']))); + if (!empty($warningOrder['traceList'])) { + $lastTrace = $warningOrder['traceList'][0]; + ExcelTool::setCellValue($activeSheet, $column++, $row, ($lastTrace['statusTime'] . ':' . $lastTrace['desc'])); + } else { + ExcelTool::setCellValue($activeSheet, $column++, $row, '--'); + } + ExcelTool::setCellValue($activeSheet, $column++, $row, $warningOrder['orderSn']); + ExcelTool::setCellValue($activeSheet, $column++, $row, OrderConst::getOrderStatusText($warningOrder['orderStatus'], $warningOrder['refundStatus'])); + ExcelTool::setCellValue($activeSheet, $column++, $row, $warningOrder['fullname']); + ExcelTool::setCellValue($activeSheet, $column++, $row, $warningOrder['fullAddress']); + $row ++; + } + } + + private function packExportCustomLogisticsWarningData(&$activeSheet, $warningOrderList) { + $logisticsMap = $this->logisticsDao->getLogisticsMap(); + $row = 2; + foreach ($warningOrderList as $warningOrder) { + $column = 1; + ExcelTool::setCellValue($activeSheet, $column++, $row, $warningOrder['mallName']); + ExcelTool::setCellValue($activeSheet, $column++, $row, $logisticsMap[$warningOrder['expressDetail']['logistics_id']]); + ExcelTool::setCellValue($activeSheet, $column++, $row, $warningOrder['expressDetail']['express_no']); + ExcelTool::setCellValue($activeSheet, $column++, $row, HtmlTool::renderLogisticsStatus($warningOrder['logisticsStatus'])); + ExcelTool::setCellValue($activeSheet, $column++, $row, strip_tags(HtmlTool::buildLogisticsWarningHtml($warningOrder['logisticsOvertimeType'], $warningOrder['logisticsStatus']))); + if (!empty($warningOrder['traceList'])) { + $lastTrace = $warningOrder['traceList'][0]; + ExcelTool::setCellValue($activeSheet, $column++, $row, ($lastTrace['statusTime'] . ':' . $lastTrace['desc'])); + } else { + ExcelTool::setCellValue($activeSheet, $column++, $row, '--'); + } + ExcelTool::setCellValue($activeSheet, $column++, $row, $warningOrder['orderSn']); + ExcelTool::setCellValue($activeSheet, $column++, $row, $warningOrder['fullname']); + ExcelTool::setCellValue($activeSheet, $column++, $row, $warningOrder['fullAddress']); + $row ++; + } + } + + private function getOpExportWarningOrderHeaders() { + return [ + '店铺名称', + '快递公司', + '运单号', + '包裹状态', + '发货时间', + '预警信息', + '最新物流信息', + '订单号', + '订单状态', + '收货人', + '收货地址', + ]; + } + + private function getCustomExportWarningOrderHeaders() { + return [ + '店铺名称', + '快递公司', + '运单号', + '包裹状态', + '预警信息', + '最新物流信息', + '订单号', + '收货人', + '收货地址', + ]; + } +} \ No newline at end of file diff --git a/app/libs/services/Order/OrderSendService.php b/app/libs/services/Order/OrderSendService.php index 2bd6d3a..b8af8bb 100644 --- a/app/libs/services/Order/OrderSendService.php +++ b/app/libs/services/Order/OrderSendService.php @@ -413,6 +413,51 @@ class OrderSendService extends AbstractService { return $this->opOrderOutstorageTaskDao->getMallProcessingTask($mallId); } + public function orderOutstoragePreManual($mallId, $deliveryInfos) { + $orderIds = ZcArrayHelper::getSub($deliveryInfos, 'orderId'); + $logisticsIds = ZcArrayHelper::getSub($deliveryInfos, 'logisticsId'); + + $logisticsIdCompanyIdMap = $this->logisticsPlatformDao->getLogisticsIdAndCompanyIdMap($logisticsIds, AppConst::appPlatformPdd); + $orders = $this->opOrderDao->getMapByIds($orderIds); + $authMallIds = array_values(array_unique(ZcArrayHelper::getSub($orders, 'mallId'))); + $authMalls = PermissionTool::checkMultiShopValid($mallId, $authMallIds); + + $orderSnErrorMap = []; + + $fCnt = 0; + $sCnt = 0; + foreach ($deliveryInfos as $data) { + $orderId = $data['orderId']; + $order = $orders[$orderId]; + $expressNo = $data['expressNo']; + $logisticsId = $data['logisticsId']; + $accessToken = $authMalls[$order['mallId']]['accessToken']; + $companyId = $logisticsIdCompanyIdMap[$logisticsId]; + if (empty($expressNo)) { + $orderSnErrorMap[$order['orderSn']] = '运单号为空'; + $fCnt++; + continue; + } + + $deliveryInfo = $this->buildDeliveryInfo($order['orderSn'], $logisticsId, $companyId, $expressNo); + $updateRet = $this->logisticsSend($order['mallId'], $mallId, $deliveryInfo, $accessToken, null, false, PurchaseOrderConst::outstorageSourcePreManual); + if (CommonTool::isSuccessRet($updateRet)) { + // TODO + // $this->opOrderService->rsyncOpOrderByOrderSns($order['mallId'], [$data['orderSn']], $accessToken); + $sCnt ++; + } else { + $orderSnErrorMap[$order['orderSn']] = $updateRet['reason']; + $fCnt ++; + } + } + + return [ + 'orderSnErrorMap' => $orderSnErrorMap, + 'fCnt' => $fCnt, + 'sCnt' => $sCnt + ]; + } + public function orderOutstorage($deliveryInfos, $source, $operatorInfo, $isReturn = false) { $operatorMallId = $operatorInfo['mallId']; diff --git a/app/libs/services/PendingMaster/PendingMatterService.php b/app/libs/services/PendingMaster/PendingMatterService.php new file mode 100644 index 0000000..f0816a0 --- /dev/null +++ b/app/libs/services/PendingMaster/PendingMatterService.php @@ -0,0 +1,308 @@ +mallSDao = MallSDao::instance(); + $this->opOrderDao = OpOrderDao::instance(); + $this->pendingMatterDao = PendingMatterDao::instance(); + $this->pendingMatterCategoryDao = PendingMatterCategoryDao::instance(); + $this->pendingMatterBufferDao = PendingMatterBufferDao::instance(); + $this->pendingMasterQueueDao = PendingMasterQueueDao::instance(); + } + + public function deletePendingMatterCategory($mallId, $pendingMatterCategoryId) { + if (CommonTool::anyEmpty($mallId, $pendingMatterCategoryId)) { + throw new CheckClientException('参数错误'); + } + $trans = DbTool::beginTrans(PendingMatterDao::instance()); + $this->pendingMatterCategoryDao->delete('pending_matter_category_id = %i and mall_id = %i', $pendingMatterCategoryId, $mallId); + $updatePendingMatterData = [ + 'pending_matter_category_id' => 0, + ]; + $this->pendingMatterDao->update($updatePendingMatterData, 'pending_matter_category_id = %i', $pendingMatterCategoryId); + DbTool::commitTrans($trans); + } + + public function savePendingMatterCategory($mallId, $pendingMatterCategoryId, $categoryName) { + if (CommonTool::anyEmpty($mallId, $categoryName)) { + throw new CheckClientException('参数错误'); + } + $data = [ + 'mall_id' => $mallId, + 'category_name' => $categoryName, + ]; + if ($pendingMatterCategoryId) { + $affect = $this->pendingMatterCategoryDao->update($data, 'pending_matter_category_id = %i and mall_id = %i', $pendingMatterCategoryId, $mallId); + } else { + $affect = $this->pendingMatterCategoryDao->insert($data); + } + if ($affect === false) { + throw new BizException('保存失败'); + } + } + + public function searchPendingMatterCategoryList($mallId, $page, $pageSize) { + return $this->pendingMatterCategoryDao->searchPage($mallId, $page, $pageSize); + } + + public function getAllPendingMatterCategoryList($mallId) { + return $this->pendingMatterCategoryDao->getAllByMallId($mallId); + } + + public function getOrderPendingMattersByPendingMatterIds($pendingMatterIds) { + return $this->pendingMatterDao->getListByIds($pendingMatterIds); + } + + private function checkOrderPendingMatterData($params) { + if (empty($params['orderSn'])) { + throw new CheckClientException('请输入订单号'); + } + if (empty($params['mallId'])) { + throw new CheckClientException('请选择店铺'); + } + $orderInfo = $this->opOrderDao->getByOrderSn($params['orderSn']); + if (empty($orderInfo)) { + throw new CheckClientException('订单不存在 或者 未同步'); + } + if ($orderInfo['mallId'] != $params['mallId']) { + throw new CheckClientException('订单所属店铺与选择的不一致'); + } + if (!empty($params['isTimerRemind']) && empty($params['gmtRemind'])) { + throw new CheckClientException('未设置提醒时间'); + } + } + + public function saveOrderPendingMatter($pendingMatterData) { + $this->checkOrderPendingMatterData($pendingMatterData); + + $orderMallId = $pendingMatterData['mallId']; + $pendingMatterId = $pendingMatterData['pendingMatterId']; + $isTimerRemind = empty($pendingMatterData['isTimerRemind']) ? 0 : 1; + $gmtRemind = $isTimerRemind && !empty($pendingMatterData['gmtRemind']) ? $pendingMatterData['gmtRemind'] : null; + if ($gmtRemind) { + $gmtRemind = date('Y-m-d H:i:s', strtotime($gmtRemind)); + } + $data = [ + 'mall_id' => $pendingMatterData['mallId'], + 'order_sn' => $pendingMatterData['orderSn'], + 'is_timer_remind' => $isTimerRemind, + 'gmt_remind' => $gmtRemind, + 'pending_matter_category_id' => empty($pendingMatterData['pendingMatterCategoryId']) ? 0 : $pendingMatterData['pendingMatterCategoryId'], + 'desc' => empty($pendingMatterData['desc']) ? null : $pendingMatterData['desc'], + 'status' => !empty($pendingMatterData['status']) && in_array($pendingMatterData['status'], [StatusConst::wait, StatusConst::finish]) ? $pendingMatterData['status'] : StatusConst::wait, + ]; + + $trans = DbTool::beginTrans(PendingMatterDao::class); + if ($pendingMatterId) { + $this->pendingMatterDao->update($data, 'pending_matter_id = %i', $pendingMatterId); + } else { + $this->pendingMatterDao->insert($data); + $pendingMatterId = $this->pendingMatterDao->lastInsertId(); + } + + if (!$isTimerRemind) { + $this->pendingMatterBufferDao->delete('mall_id = %i and pending_matter_id = %i', $orderMallId, $pendingMatterId); + $this->pendingMasterQueueDao->delete('mall_id = %i and pending_matter_id = %i', $orderMallId, $pendingMatterId); + } else { + $this->insertUpdatePendingMatterBuffer($orderMallId, $pendingMatterId, $gmtRemind); + } + DbTool::commitTrans($trans); + } + + private function insertUpdatePendingMatterBuffer($mallId, $pendingMatterId, $gmtRemind) { + if (CommonTool::anyEmpty($mallId, $pendingMatterId, $gmtRemind)) { + return false; + } + $updateData = [ + 'mall_id' => $mallId, + 'pending_matter_id' => $pendingMatterId, + 'gmt_exec' => $gmtRemind, + ]; + return $this->pendingMatterBufferDao->insertUpdate($updateData); + } + + public function searchOrderPendingMatterList($mallId, $params) { + $page = intval($params['page'] ?: 1); + $pageSize = intval($params['pageSize'] ?: 20); + $filter = $this->getOrderPendingMatterFilter($params); + list($pendingMatterList, $total) = $this->pendingMatterDao->searchPage($mallId, $filter, $page, $pageSize); + if (empty($pendingMatterList)) { + return []; + } + $pendingMatterCategoryIds = ZcArrayHelper::getSub($pendingMatterList, 'pendingMatterCategoryId'); + $pendingMatterCategoryIds = array_unique(array_filter($pendingMatterCategoryIds, 'isNumeric')); + $mallIds = array_column($pendingMatterList, 'mallId'); + $mallIdAndMallNameMap = $this->mallSDao->getMallIdAndMallNameMap($mallIds); + $categoryIdAndPendingMatterCategoryInfoMap = $this->getPendingMatterCategoryListByCategoryIds($pendingMatterCategoryIds); + foreach ($pendingMatterList as &$pendingMatter) { + $categoryName = $categoryIdAndPendingMatterCategoryInfoMap[$pendingMatter['pendingMatterCategoryId']]['categoryName']; + if ($pendingMatter['pendingMatterCategoryId'] == 0) { + $categoryName = '默认分类'; + } + $pendingMatter['mallName'] = $mallIdAndMallNameMap[$pendingMatter['mallId']]; + $pendingMatter['categoryName'] = $categoryName; + } + return [$pendingMatterList, $total]; + } + + private function getOrderPendingMatterFilter($params) { + $filter = []; + if (!empty($params['authMallIds'])) { + $filter['authMallIds'] = is_array($params['authMallIds']) ? $params['authMallIds'] : [$params['authMallIds']]; + } + if (!empty($params['orderSn'])) { + $filter['orderSn'] = is_array($params['orderSn']) ? $params['orderSn'] : CommonTool::splitWithComma($params['orderSn']); + } + if (isset($params['pendingMatterCategoryId']) && is_numeric($params['pendingMatterCategoryId'])) { + $filter['pendingMatterCategoryId'] = $params['pendingMatterCategoryId']; + } + if (!empty($params['status']) && in_array($params['status'], [StatusConst::wait, StatusConst::finish])) { + $filter['status'] = $params['status']; + } + return $filter; + } + + public function getPendingMatterCategoryListByCategoryIds($pendingMatterCategoryIds) { + return $this->pendingMatterCategoryDao->getMapByIds($pendingMatterCategoryIds); + } + + public function deletePendingMatter($pendingMatterIds) { + if (empty($pendingMatterIds)) { + return false; + } + $pendingMatterIds = is_array($pendingMatterIds) ? $pendingMatterIds : [$pendingMatterIds]; + $trans = DbTool::beginTrans(PendingMatterDao::class); + $this->pendingMatterDao->delete('pending_matter_id IN %li', $pendingMatterIds); + $this->pendingMatterBufferDao->delete('pending_matter_id IN %li', $pendingMatterIds); + $this->pendingMasterQueueDao->delete('pending_matter_id IN %li', $pendingMatterIds); + DbTool::commitTrans($trans); + } + + public function markPendingMatter($mallId, $pendingMatterId, $status) { + if (CommonTool::anyEmpty($pendingMatterId, $status)) { + return false; + } + $pendingMatterInfo = $this->pendingMatterDao->getById($pendingMatterId); + if (!$status || !$pendingMatterId || !$pendingMatterInfo) { + throw new BizException('参数错误'); + } + + PermissionTool::checkMultiShopValid($mallId, [$pendingMatterInfo['mallId']]); + + $pendingMatterInfo = $this->pendingMatterDao->getById($pendingMatterId); + + $trans = DbTool::beginTrans(PendingMatterDao::class); + $updateData = [ + 'status' => $status, + ]; + $this->pendingMatterDao->update($updateData, 'pending_matter_id = %i', $pendingMatterId); + if ($status == StatusConst::finish) { + $this->pendingMatterBufferDao->delete('pending_matter_id = %i', $pendingMatterId); + $this->pendingMasterQueueDao->delete('pending_matter_id = %i', $pendingMatterId); + } + if ($status == StatusConst::wait && $pendingMatterInfo['isTimerRemind'] && $pendingMatterInfo['gmtRemind'] && (strtotime($pendingMatterInfo['gmtRemind']) > time())) { + $this->insertUpdatePendingMatterBuffer($pendingMatterInfo['mallId'], $pendingMatterId, $pendingMatterInfo['gmtRemind']); + } + DbTool::commitTrans($trans); + } + + public function getOrderPendingMatter($mallId, $pendingMatterId) { + $pendingMatterInfo = $this->pendingMatterDao->getById($pendingMatterId); + + if (!$pendingMatterInfo) { + throw new BizException('待处理事项不存在'); + } + PermissionTool::checkMultiShopValid($mallId, [$pendingMatterInfo['mallId']]); + return [ + 'pendingMatterId' => $pendingMatterInfo['pendingMatterId'], + 'pendingMatterCategoryId' => $pendingMatterInfo['pendingMatterCategoryId'], + 'mallId' => $pendingMatterInfo['mallId'], + 'orderSn' => $pendingMatterInfo['orderSn'], + 'isTimerRemind' => $pendingMatterInfo['isTimerRemind'], + 'gmtRemind' => $pendingMatterInfo['gmtRemind'], + 'desc' => $pendingMatterInfo['desc'], + 'status' => $pendingMatterInfo['status'], + ]; + } + + public function getOrderPendingMatterCount($orderSn) { + $orderSn = CommonTool::convertValToArray($orderSn); + $orderSnAndPendingMatterCountMap = $this->pendingMatterDao->getOrderSnAndCountMap($orderSn); + $data = []; + foreach ($orderSnAndPendingMatterCountMap as $orderSnAndPendingMatterCountInfo) { + $data[] = [ + 'orderSn' => $orderSnAndPendingMatterCountInfo['orderSn'], + 'count' => $orderSnAndPendingMatterCountInfo['pendingMatterCount'], + ]; + } + return $data; + } + + public function exportPendingMatter($mallId, $params) { + $orderPendingMatterData = $this->getExportPendingMatter($mallId, $params); + $objPHPExcel = new \PHPExcel(); + $activeSheet = ExcelTool::createNewSheetAndSetTitle($objPHPExcel, 0); + $headers = ['店铺', '订单号', '事项描述', '事项分类', '提醒时间', '状态']; + ExcelTool::setSheetRowValues($activeSheet, 1, $headers); + + $row = 2; + foreach ($orderPendingMatterData as $orderPendingMatter) { + $column = 1; + ExcelTool::setCellValue($activeSheet, $column++, $row, empty($orderPendingMatter['mallName']) ? '' : $orderPendingMatter['mallName']); + ExcelTool::setCellValue($activeSheet, $column++, $row, $orderPendingMatter['orderSn']); + ExcelTool::setCellValue($activeSheet, $column++, $row, $orderPendingMatter['desc']); + ExcelTool::setCellValue($activeSheet, $column++, $row, empty($orderPendingMatter['categoryName']) ? '' : $orderPendingMatter['categoryName']); + + $gmtRemind = $orderPendingMatter['isTimerRemind'] ? $orderPendingMatter['gmtRemind'] : ''; + ExcelTool::setCellValue($activeSheet, $column++, $row, $gmtRemind); + ExcelTool::setCellValue($activeSheet, $column++, $row, $orderPendingMatter['status'] == StatusConst::finish ? '已处理' : '未处理'); + $row++; + } + ExcelTool::downloadExcel($objPHPExcel, date('Y-m-d', time()) . '-待处理事项'); + return false; + } + + private function getExportPendingMatter($mallId, $params) { + $page = 1; + $pageSize = 50; + $orderPendingMatterList = []; + while (true) { + $params['page'] = $page; + $params['pageSize'] = $pageSize; + list($pendingMatterList, $total) = $this->searchOrderPendingMatterList($mallId, $params); + if (empty($pendingMatterList)) { + break; + } + $orderPendingMatterList = array_merge($orderPendingMatterList, $pendingMatterList); + if (count($pendingMatterList) < $pageSize) { + break; + } + } + return $orderPendingMatterList; + } +} \ No newline at end of file diff --git a/app/libs/tool/class.HtmlTool.php b/app/libs/tool/class.HtmlTool.php index 59fa644..421dbe7 100644 --- a/app/libs/tool/class.HtmlTool.php +++ b/app/libs/tool/class.HtmlTool.php @@ -187,4 +187,70 @@ class HtmlTool { } return self::getStaticFile($files, $forceTimestamp); } + + public static function renderLogisticsStatus($logisticsStatus) { + switch ($logisticsStatus) { + case OrderPrintConst::logisticsActionGot: + return '已揽件'; + case OrderPrintConst::logisticsActionSend: + return '派件'; + case OrderPrintConst::logisticsActionSign: + return '签收'; + case OrderPrintConst::logisticsActionRejection: + return '拒签'; + case OrderPrintConst::logisticsActionReturn: + return '退件'; + case OrderPrintConst::logisticsActionArrival: + case OrderPrintConst::logisticsActionDeparture: + return '流转中'; + case OrderPrintConst::logisticsActionFail: + return '问题件'; + case OrderPrintConst::logisticsActionStayInWarehouse: + return '留仓'; + case OrderPrintConst::logisticsActionSignOnBehalf: + return '代收点代签'; + case OrderPrintConst::logisticsActionOther: + return '其他'; + case OrderPrintConst::logisticsActionInCabinet: + return '入代收点'; + case OrderPrintConst::logisticsActionOutCabinet: + return '出代收点'; + case OrderPrintConst::logisticsActionClearanceStart: + return '清关中'; + case OrderPrintConst::logisticsActionClearanceFinish: + return '清关完成'; + } + return '-'; + } + + public static function buildLogisticsWarningHtml($warningType, $logisticsStatus) { + if (in_array($logisticsStatus, OrderPrintConst::getLogisticsRejectActions())) { + return '买家拒收'; + } + switch ($warningType) { + case OrderPrintConst::logisticsFilterOvertimeGot: + return '超时未揽收'; + case OrderPrintConst::logisticsFilterOvertimeNoArrival: + return '超时未流转'; + case OrderPrintConst::logisticsFilterOvertimeNoNewTrace: + return '超时无物流更新'; + case OrderPrintConst::logisticsFilterOvertimeNoSign: + return '超时未签收'; + case OrderPrintConst::logisticsFilterRejection: + return '买家拒收'; + case OrderPrintConst::logisticsFilterAllocateStay: + return '分拨停留'; + case OrderPrintConst::logisticsFilterNodeStayJZHW: + return '江浙沪皖节点停留'; + case OrderPrintConst::logisticsFilterNodeStayJJJ: + return '京津冀节点停留'; + case OrderPrintConst::logisticsFilterNodeStayTYSF: + return '同意省份节点停留'; + case OrderPrintConst::logisticsFilterNodeStayBTSF: + return '不同省份节点停留'; + case OrderPrintConst::logisticsFilterNodeStayXXN: + return '任一地址在新疆、西藏或内蒙古节点停留'; + + } + } } \ No newline at end of file diff --git a/app/libs/tool/class.PddApi.php b/app/libs/tool/class.PddApi.php index ec744bb..a7fdccc 100644 --- a/app/libs/tool/class.PddApi.php +++ b/app/libs/tool/class.PddApi.php @@ -474,4 +474,51 @@ class PddApi extends PddApiAbstract { return [$waybillRetList, $needQueryDtos]; } + + public static function getRefundAddressList($accessToken) { + $req = new PddRefundAddressListGet(); + $response = self::getClient()->execute($req, $accessToken); + return self::handleResponse($response); + } + + public static function fulfillmentSend($deliveryInfo, $accessToken) { + if (CommonTool::isForbidRequestOrder()) { + return CommonTool::failResult('禁止请求该接口'); + } + + $req = new PddLogisticsFulfillmentSendRequest(); + $req->setFulfillmentSn($deliveryInfo['fulfillmentSn']); + $req->setLogisticsId($deliveryInfo['companyId']); + $req->setTrackingNumber($deliveryInfo['trackingNumber']); + if (!empty($deliveryInfo['redeliveryType'])) { + $req->setRedeliveryType($deliveryInfo['redeliveryType']); + } + + if ($deliveryInfo['returnAddressId']) { + $req->setReturnAddressId($deliveryInfo['returnAddressId']); + } + + $response = self::getClient()->execute($req, $accessToken); + return self::handleResponse($response); + } + + public static function getPddLogisticsTrace($companyCode, $mailNo, $cache) { + $req = new PddLogisticsOrdertraceGet(); + $req->setCompanyCode($companyCode); + $req->setMailNo($mailNo); + $req->setCache($cache); + + $response = self::getClient()->execute($req); + return self::handleResponse($response); + } + + public static function pddLogisticsIsvTraceNotifySub($companyCode, $expressNo, $tel) { + $req = new PddLogisticsIsvTraceNotifySub(); + $req->setShipCode($companyCode); + $req->setTrackNo($expressNo); + $req->setTel($tel); + + $response = self::getClient()->execute($req); + return self::handleResponse($response); + } } \ No newline at end of file