|
|
@@ -3460,14 +3460,16 @@ class Procuremen extends Backend
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 新下发/重新下发:同订单号下「其它有明确批次号」的未完结主单记 mod_rq 软删除。
|
|
|
+ * 新下发/重新下发:同订单号+同工序下「其它有明确批次号」的未完结主单记 mod_rq 软删除。
|
|
|
* 不处理:本批保留行、无批次号旧数据、已完结单(避免误伤生产并行工序)。
|
|
|
*
|
|
|
* @param array<int, string> $ccydhs
|
|
|
* @param array<int, int|string> $keepScydgyIds 保留的工序 ID(本批)
|
|
|
* @param string $keepBatchNo 本批批次号(同批其它工序行也保留)
|
|
|
+ * @param array<int, string> $cgySet 本批工序名称集合(防止同订单不同工序被误删)
|
|
|
+ * @return array<int, true> 实际被软删的 scydgy_id 集合
|
|
|
*/
|
|
|
- protected function softDeleteOtherBatchPurchaseOrders(array $ccydhs, array $keepScydgyIds = [], string $keepBatchNo = ''): void
|
|
|
+ protected function softDeleteOtherBatchPurchaseOrders(array $ccydhs, array $keepScydgyIds = [], string $keepBatchNo = '', array $cgySet = []): array
|
|
|
{
|
|
|
$ccydhList = [];
|
|
|
foreach ($ccydhs as $c) {
|
|
|
@@ -3478,7 +3480,7 @@ class Procuremen extends Backend
|
|
|
$keepBatchNo = trim($keepBatchNo);
|
|
|
// 无本批批次号时不做软删,避免把同订单其它有效工序一并清掉
|
|
|
if ($ccydhList === [] || $keepBatchNo === '') {
|
|
|
- return;
|
|
|
+ return [];
|
|
|
}
|
|
|
$keepSid = [];
|
|
|
foreach ($keepScydgyIds as $sid) {
|
|
|
@@ -3498,6 +3500,19 @@ class Procuremen extends Backend
|
|
|
->whereRaw("order_batch_no <> '{$bnEsc}'")
|
|
|
// 已完结不软删
|
|
|
->whereRaw('NOT (' . ProcuremenStatus::sqlPoCompleted('status') . ')');
|
|
|
+ // 按工序名称隔离,防止同订单不同工序被误删
|
|
|
+ if ($cgySet !== []) {
|
|
|
+ $cgyEscList = [];
|
|
|
+ foreach ($cgySet as $cgy) {
|
|
|
+ $cgyEsc = str_replace(["\\", "'"], ["\\\\", "''"], trim((string)$cgy));
|
|
|
+ if ($cgyEsc !== '') {
|
|
|
+ $cgyEscList[] = "'" . $cgyEsc . "'";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if ($cgyEscList !== []) {
|
|
|
+ $q->whereRaw("CGYMC IN (" . implode(',', $cgyEscList) . ")");
|
|
|
+ }
|
|
|
+ }
|
|
|
if ($keepSid !== []) {
|
|
|
$q->where('scydgy_id', 'not in', array_keys($keepSid));
|
|
|
}
|
|
|
@@ -3506,8 +3521,18 @@ class Procuremen extends Backend
|
|
|
'manual_pick' => 0,
|
|
|
'manual_pick_reason' => '',
|
|
|
]);
|
|
|
+ // 返回本次实际被软删的 scydgy_id,供调用方废弃明细用
|
|
|
+ return Db::table('purchase_order')
|
|
|
+ ->where('CCYDH', 'in', array_keys($ccydhList))
|
|
|
+ ->whereRaw("(mod_rq IS NULL OR mod_rq = '' OR mod_rq LIKE '0000-00-00%')")
|
|
|
+ ->whereRaw("TRIM(CAST(order_batch_no AS CHAR(64))) <> ''")
|
|
|
+ ->whereRaw("order_batch_no <> '{$bnEsc}'")
|
|
|
+ ->whereRaw('NOT (' . ProcuremenStatus::sqlPoCompleted('status') . ')')
|
|
|
+ ->where('mod_rq', $now)
|
|
|
+ ->column('scydgy_id');
|
|
|
} catch (\Throwable $e) {
|
|
|
Log::write('softDeleteOtherBatchPurchaseOrders: ' . $e->getMessage(), 'error');
|
|
|
+ return [];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -8894,6 +8919,10 @@ class Procuremen extends Backend
|
|
|
if (in_array($scene, ['confirm_ok_email', 'confirm_fail_email'], true)) {
|
|
|
$this->ensureConfirmResultEmailTemplates();
|
|
|
}
|
|
|
+ if (in_array($scene, ['review_email', 'review_sms'], true)) {
|
|
|
+ $this->ensureReviewEmailTemplate();
|
|
|
+ $this->ensureReviewSmsTemplate();
|
|
|
+ }
|
|
|
try {
|
|
|
$row = Db::table('purchase_sms_template')
|
|
|
->where('scene', $scene)
|
|
|
@@ -9871,6 +9900,8 @@ class Procuremen extends Backend
|
|
|
$orderTypeCtx = $this->resolveIssueNotifyOrderTypeFromBundle($bundle);
|
|
|
$ctx['order_type'] = (string)($orderTypeCtx['order_type'] ?? '');
|
|
|
$ctx['score_weights'] = (string)($orderTypeCtx['score_weights'] ?? '');
|
|
|
+ $this->ensureReviewEmailTemplate();
|
|
|
+ $this->ensureReviewSmsTemplate();
|
|
|
$notifyBundle = $this->composeSupplierNotifyBundle($chosen, $ctx, $detailLinks, $emailTplScene);
|
|
|
$notifyBundle['email_log_scene'] = $emailLogScene;
|
|
|
$notifyBundle['email_log_scydgy_id'] = (int)array_key_first($sids);
|
|
|
@@ -10239,6 +10270,10 @@ class Procuremen extends Backend
|
|
|
$orderType = '';
|
|
|
$scoreWeights = '';
|
|
|
$rule = null;
|
|
|
+ Log::write('procuremen resolveOrderType bundle: ' . json_encode([
|
|
|
+ 'score_rule' => isset($bundle['score_rule']) ? $bundle['score_rule'] : 'NOT_SET',
|
|
|
+ 'pos0_score_rule_id' => isset($bundle['pos'][0]['score_rule_id']) ? $bundle['pos'][0]['score_rule_id'] : 'NOT_SET',
|
|
|
+ ], JSON_UNESCAPED_UNICODE), 'notice');
|
|
|
if (!empty($bundle['score_rule']) && is_array($bundle['score_rule'])) {
|
|
|
$rule = $bundle['score_rule'];
|
|
|
}
|
|
|
@@ -10249,8 +10284,10 @@ class Procuremen extends Backend
|
|
|
if ($ruleId > 0) {
|
|
|
try {
|
|
|
$rule = ProcuremenSupplierScore::getRuleById($ruleId);
|
|
|
+ Log::write('procuremen resolveOrderType via pos ruleId=' . $ruleId . ' result: ' . json_encode($rule, JSON_UNESCAPED_UNICODE), 'notice');
|
|
|
} catch (\Throwable $e) {
|
|
|
$rule = null;
|
|
|
+ Log::write('procuremen resolveOrderType getRuleById exception: ' . $e->getMessage(), 'error');
|
|
|
}
|
|
|
}
|
|
|
if (!is_array($rule) || (int)($rule['id'] ?? 0) <= 0) {
|
|
|
@@ -10274,6 +10311,7 @@ class Procuremen extends Backend
|
|
|
if ($orderType === '' && is_array($po0)) {
|
|
|
$orderType = trim((string)($po0['score_rule_name'] ?? ''));
|
|
|
}
|
|
|
+ Log::write('procuremen resolveOrderType result: orderType=' . $orderType . ', scoreWeights=' . $scoreWeights, 'notice');
|
|
|
|
|
|
return [
|
|
|
'order_type' => $orderType,
|
|
|
@@ -10804,6 +10842,127 @@ class Procuremen extends Backend
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 确保「协助下发-邮箱」模版存在(含 {order_type};可在短信模版配置中修改)
|
|
|
+ */
|
|
|
+ protected function ensureReviewEmailTemplate(): void
|
|
|
+ {
|
|
|
+ static $done = false;
|
|
|
+ if ($done) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ $done = true;
|
|
|
+ $content = "您好,{company_name}:\n\n"
|
|
|
+ . "您有新的协助加工订单,请登录平台查看并报价。\n\n"
|
|
|
+ . "需求编号:{ccydh}\n"
|
|
|
+ . "印件名称:{cyjmc}\n"
|
|
|
+ . "业务分类:{category}\n"
|
|
|
+ . "订单类型:{order_type}\n"
|
|
|
+ . "{process_lines}\n\n"
|
|
|
+ . "请在 {deadline} 前完成报价。\n\n"
|
|
|
+ . "平台链接:{platform_url}\n";
|
|
|
+ try {
|
|
|
+ $row = Db::table('purchase_sms_template')
|
|
|
+ ->where('scene', 'review_email')
|
|
|
+ ->find();
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ $now = date('Y-m-d H:i:s');
|
|
|
+ if (is_array($row) && $row !== []) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ $data = [
|
|
|
+ 'scene' => 'review_email',
|
|
|
+ 'title' => '协助加工订单通知',
|
|
|
+ 'content' => $content,
|
|
|
+ 'remark' => '协助下发-邮箱;可在短信模版配置中修改',
|
|
|
+ 'status' => 1,
|
|
|
+ ];
|
|
|
+ $cols = Db::query("SHOW COLUMNS FROM `purchase_sms_template`");
|
|
|
+ $colNames = [];
|
|
|
+ foreach ($cols as $c) {
|
|
|
+ if (!is_array($c)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $n = (string)($c['Field'] ?? $c['field'] ?? '');
|
|
|
+ if ($n !== '') {
|
|
|
+ $colNames[$n] = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (isset($colNames['updatetime'])) {
|
|
|
+ $data['updatetime'] = $now;
|
|
|
+ }
|
|
|
+ if (isset($colNames['createtime'])) {
|
|
|
+ $data['createtime'] = $now;
|
|
|
+ }
|
|
|
+ Db::table('purchase_sms_template')->insert($data);
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ // ignore
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 确保「协助下发-短信」模版存在(含 {order_type};可在短信模版配置中修改)
|
|
|
+ */
|
|
|
+ protected function ensureReviewSmsTemplate(): void
|
|
|
+ {
|
|
|
+ static $done = false;
|
|
|
+ if ($done) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ $done = true;
|
|
|
+ $content = "您好,{company_name}:\n\n"
|
|
|
+ . "您有新的协助加工订单,请登录平台查看并报价。\n\n"
|
|
|
+ . "需求编号:{ccydh}\n"
|
|
|
+ . "印件名称:{cyjmc}\n"
|
|
|
+ . "订单类型:{order_type}\n"
|
|
|
+ . "{process_lines}\n\n"
|
|
|
+ . "请在 {deadline} 前完成报价。\n\n"
|
|
|
+ . "平台链接:{platform_url}\n";
|
|
|
+ try {
|
|
|
+ $row = Db::table('purchase_sms_template')
|
|
|
+ ->where('scene', 'review_sms')
|
|
|
+ ->find();
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ $now = date('Y-m-d H:i:s');
|
|
|
+ if (is_array($row) && $row !== []) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ $data = [
|
|
|
+ 'scene' => 'review_sms',
|
|
|
+ 'title' => '协助加工订单通知',
|
|
|
+ 'content' => $content,
|
|
|
+ 'remark' => '协助下发-短信;可在短信模版配置中修改',
|
|
|
+ 'status' => 1,
|
|
|
+ ];
|
|
|
+ $cols = Db::query("SHOW COLUMNS FROM `purchase_sms_template`");
|
|
|
+ $colNames = [];
|
|
|
+ foreach ($cols as $c) {
|
|
|
+ if (!is_array($c)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $n = (string)($c['Field'] ?? $c['field'] ?? '');
|
|
|
+ if ($n !== '') {
|
|
|
+ $colNames[$n] = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (isset($colNames['updatetime'])) {
|
|
|
+ $data['updatetime'] = $now;
|
|
|
+ }
|
|
|
+ if (isset($colNames['createtime'])) {
|
|
|
+ $data['createtime'] = $now;
|
|
|
+ }
|
|
|
+ Db::table('purchase_sms_template')->insert($data);
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ // ignore
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 确保「供应商询价通知」邮箱模版存在(查询询价-询价/发邮件;可在短信模版配置中修改)
|
|
|
*/
|
|
|
@@ -14554,6 +14713,7 @@ class Procuremen extends Backend
|
|
|
// 重新下发后需重新开标;清掉本批按订单号/批次号记录的开标验证
|
|
|
$ccydhSet = [];
|
|
|
$batchSet = [];
|
|
|
+ $cgySet = [];
|
|
|
foreach ($pos as $poRow) {
|
|
|
if (!is_array($poRow)) {
|
|
|
continue;
|
|
|
@@ -14565,6 +14725,10 @@ class Procuremen extends Backend
|
|
|
if ($bn !== '') {
|
|
|
$batchSet[$bn] = true;
|
|
|
}
|
|
|
+ $cgy = trim((string)($poRow['CGYMC'] ?? ''));
|
|
|
+ if ($cgy !== '') {
|
|
|
+ $cgySet[$cgy] = true;
|
|
|
+ }
|
|
|
}
|
|
|
$this->clearProcuremenBidOpenRecords(array_keys($ccydhSet), array_keys($batchSet));
|
|
|
$this->clearProcuremenSupplierScoresForCcydhs(array_keys($ccydhSet));
|
|
|
@@ -14574,8 +14738,21 @@ class Procuremen extends Backend
|
|
|
$batchKeys = array_keys($batchSet);
|
|
|
$keepBatch = (string)reset($batchKeys);
|
|
|
}
|
|
|
- $this->softDeleteOtherBatchPurchaseOrders(array_keys($ccydhSet), array_keys($sids), $keepBatch);
|
|
|
+ // 返回被软删的旧批次 scydgy_id,用于废弃其明细
|
|
|
+ $voidedSids = $this->softDeleteOtherBatchPurchaseOrders(array_keys($ccydhSet), array_keys($sids), $keepBatch, array_keys($cgySet));
|
|
|
+ // 废弃本批次新工序的明细(重新下发后重新招标)
|
|
|
$this->voidPurchaseOrderDetailsForScydgyIds(array_keys($sids));
|
|
|
+ // 废弃被软删旧批次的明细(防止卡在"已提交"状态)
|
|
|
+ if ($voidedSids !== []) {
|
|
|
+ $this->voidPurchaseOrderDetailsForScydgyIds($voidedSids);
|
|
|
+ // 旧批次被重新下发流程软删,记录日志便于追溯
|
|
|
+ foreach ($voidedSids as $oldSid) {
|
|
|
+ $oldSidInt = (int)$oldSid;
|
|
|
+ if ($this->isValidScydgyRowId($oldSidInt)) {
|
|
|
+ $this->addOrderLog($oldSidInt, $logAction, '重新下发:同批次工序旧数据软删', null);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
foreach (array_keys($sids) as $sid) {
|
|
|
$poIdLog = (int)($poIdBySid[$sid] ?? 0);
|