|
@@ -3153,6 +3153,7 @@ class Procuremen extends Backend
|
|
|
$pick['selected_ids'],
|
|
$pick['selected_ids'],
|
|
|
$pick['unselected_ids'],
|
|
$pick['unselected_ids'],
|
|
|
(int)$pick['purchase_order_id'],
|
|
(int)$pick['purchase_order_id'],
|
|
|
|
|
+ false,
|
|
|
false
|
|
false
|
|
|
);
|
|
);
|
|
|
}
|
|
}
|
|
@@ -3163,6 +3164,13 @@ class Procuremen extends Backend
|
|
|
$this->error($msg !== '' ? $msg : '提交失败');
|
|
$this->error($msg !== '' ? $msg : '提交失败');
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ try {
|
|
|
|
|
+ $bundle = $this->loadOrderBundleForConfirmNotify(array_column($picks, 'scydgy_id'));
|
|
|
|
|
+ $this->dispatchPurchaseConfirmPickNotifications($bundle, $results);
|
|
|
|
|
+ } catch (\Throwable $e) {
|
|
|
|
|
+ Log::write('采购确认短信批量发送异常: ' . $e->getMessage(), 'error');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
$this->pickHiddenScydgySetCache = null;
|
|
$this->pickHiddenScydgySetCache = null;
|
|
|
$this->success('操作成功', '', ['batch' => $results]);
|
|
$this->success('操作成功', '', ['batch' => $results]);
|
|
|
}
|
|
}
|
|
@@ -3170,7 +3178,7 @@ class Procuremen extends Backend
|
|
|
/**
|
|
/**
|
|
|
* @return array<string, mixed>
|
|
* @return array<string, mixed>
|
|
|
*/
|
|
*/
|
|
|
- protected function runPurchaseConfirmPick(int $sid, array $selectedIds, array $unselectedIds, int $purchaseOrderId, bool $manageTransaction = true): array
|
|
|
|
|
|
|
+ protected function runPurchaseConfirmPick(int $sid, array $selectedIds, array $unselectedIds, int $purchaseOrderId, bool $manageTransaction = true, bool $sendNotifications = true): array
|
|
|
{
|
|
{
|
|
|
$poRow = ProcuremenGuard::loadPurchaseOrderOrFail($sid);
|
|
$poRow = ProcuremenGuard::loadPurchaseOrderOrFail($sid);
|
|
|
ProcuremenGuard::assertWflowPendingApproval($poRow);
|
|
ProcuremenGuard::assertWflowPendingApproval($poRow);
|
|
@@ -3281,8 +3289,131 @@ class Procuremen extends Backend
|
|
|
$poIdFinal > 0 ? $poIdFinal : null
|
|
$poIdFinal > 0 ? $poIdFinal : null
|
|
|
);
|
|
);
|
|
|
|
|
|
|
|
- $confirmNotifyVars = $this->buildPurchaseConfirmNotifyVars($sid, $selectedIds[0] ?? 0);
|
|
|
|
|
|
|
+ if ($sendNotifications) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ $bundle = $this->loadOrderBundleForConfirmNotify([$sid]);
|
|
|
|
|
+ $this->dispatchPurchaseConfirmPickNotifications($bundle, [[
|
|
|
|
|
+ 'scydgy_id' => $sid,
|
|
|
|
|
+ 'selected_ids' => $selectedIds,
|
|
|
|
|
+ 'unselected_ids' => $unselectedIds,
|
|
|
|
|
+ 'purchase_order_id' => $purchaseOrderId,
|
|
|
|
|
+ ]]);
|
|
|
|
|
+ } catch (\Throwable $e) {
|
|
|
|
|
+ Log::write('采购确认短信发送异常 scydgy_id=' . $sid . ' ' . $e->getMessage(), 'error');
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Log::write(sprintf(
|
|
|
|
|
+ 'purchaseConfirmPick scydgy_id=%s purchase_order_id=%d selected_ids=%s unselected_ids=%s',
|
|
|
|
|
+ $scydgyId,
|
|
|
|
|
+ $purchaseOrderId,
|
|
|
|
|
+ json_encode($selectedIds, JSON_UNESCAPED_UNICODE),
|
|
|
|
|
+ json_encode($unselectedIds, JSON_UNESCAPED_UNICODE)
|
|
|
|
|
+ ), 'notice');
|
|
|
|
|
+
|
|
|
|
|
+ $pdfPublicPath = '';
|
|
|
|
|
+ try {
|
|
|
|
|
+ $pdfPublicPath = (string)$this->savePurchaseConfirmDetailPdf($sid, $poIdFinal);
|
|
|
|
|
+ } catch (\Throwable $e) {
|
|
|
|
|
+ Log::write('采购确认PDF异常: ' . $e->getMessage(), 'error');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return [
|
|
|
|
|
+ 'scydgy_id' => $scydgyId,
|
|
|
|
|
+ 'purchase_order_id' => $purchaseOrderId,
|
|
|
|
|
+ 'selected_ids' => $selectedIds,
|
|
|
|
|
+ 'unselected_ids' => $unselectedIds,
|
|
|
|
|
+ 'purchase_confirm_pdf' => $pdfPublicPath,
|
|
|
|
|
+ ];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 审批通过短信:按本次涉及的工序汇总 process_lines
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param int[]|string[] $scydgyIds
|
|
|
|
|
+ * @return array{ccydh:string, pos:array<int,array>, merge_rows:array<int,array>}
|
|
|
|
|
+ */
|
|
|
|
|
+ protected function loadOrderBundleForConfirmNotify(array $scydgyIds): array
|
|
|
|
|
+ {
|
|
|
|
|
+ $empty = ['ccydh' => '', 'pos' => [], 'merge_rows' => []];
|
|
|
|
|
+ $scydgyIds = array_values(array_unique(array_filter(array_map('intval', $scydgyIds))));
|
|
|
|
|
+ if ($scydgyIds === []) {
|
|
|
|
|
+ return $empty;
|
|
|
|
|
+ }
|
|
|
|
|
+ $pos = [];
|
|
|
|
|
+ try {
|
|
|
|
|
+ $rows = Db::table('purchase_order')->where('scydgy_id', 'in', $scydgyIds)->order('scydgy_id', 'asc')->select();
|
|
|
|
|
+ } catch (\Throwable $e) {
|
|
|
|
|
+ $rows = [];
|
|
|
|
|
+ }
|
|
|
|
|
+ if (is_array($rows)) {
|
|
|
|
|
+ foreach ($rows as $po) {
|
|
|
|
|
+ if (is_array($po)) {
|
|
|
|
|
+ $pos[] = $po;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if ($pos === []) {
|
|
|
|
|
+ return $empty;
|
|
|
|
|
+ }
|
|
|
|
|
+ $ccydh = trim((string)($pos[0]['CCYDH'] ?? ''));
|
|
|
|
|
+
|
|
|
|
|
+ return [
|
|
|
|
|
+ 'ccydh' => $ccydh,
|
|
|
|
|
+ 'pos' => $pos,
|
|
|
|
|
+ 'merge_rows' => $this->scydgyRowsForPurchaseOrders($pos),
|
|
|
|
|
+ ];
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 审批通过/未通过短信:同一供应商只发一条,process_lines 含本次全部工序
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param array{ccydh?:string,pos?:array,merge_rows?:array} $bundle
|
|
|
|
|
+ * @param array<int, array<string, mixed>> $picks
|
|
|
|
|
+ */
|
|
|
|
|
+ protected function dispatchPurchaseConfirmPickNotifications(array $bundle, array $picks): void
|
|
|
|
|
+ {
|
|
|
|
|
+ if ($picks === []) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ $fallbackDetailId = 0;
|
|
|
|
|
+ $winners = [];
|
|
|
|
|
+ $losers = [];
|
|
|
|
|
+ foreach ($picks as $pick) {
|
|
|
|
|
+ if (!is_array($pick)) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ $sid = (int)($pick['scydgy_id'] ?? 0);
|
|
|
|
|
+ if (!$this->isValidScydgyRowId($sid)) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ $selectedIds = array_values(array_unique(array_filter(array_map('intval', (array)($pick['selected_ids'] ?? [])))));
|
|
|
|
|
+ $unselectedIds = array_values(array_unique(array_filter(array_map('intval', (array)($pick['unselected_ids'] ?? [])))));
|
|
|
|
|
+ if ($fallbackDetailId <= 0 && $selectedIds !== []) {
|
|
|
|
|
+ $fallbackDetailId = (int)$selectedIds[0];
|
|
|
|
|
+ }
|
|
|
|
|
+ foreach ($selectedIds as $pid) {
|
|
|
|
|
+ $dr = $this->purchaseOrderDetai($sid, $pid);
|
|
|
|
|
+ if (!is_array($dr)) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ $winners[$this->notifySupplierDedupeKey($dr)] = $dr;
|
|
|
|
|
+ }
|
|
|
|
|
+ foreach ($unselectedIds as $pid) {
|
|
|
|
|
+ $dr = $this->purchaseOrderDetai($sid, $pid);
|
|
|
|
|
+ if (!is_array($dr)) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ $key = $this->notifySupplierDedupeKey($dr);
|
|
|
|
|
+ if (!isset($winners[$key])) {
|
|
|
|
|
+ $losers[$key] = $dr;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if ($winners === [] && $losers === []) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ $confirmNotifyVars = $this->buildPurchaseConfirmNotifyVars(0, $fallbackDetailId, $bundle);
|
|
|
$sendSmsSafe = function ($phone, $content) {
|
|
$sendSmsSafe = function ($phone, $content) {
|
|
|
$phone = trim((string)$phone);
|
|
$phone = trim((string)$phone);
|
|
|
if ($phone === '') {
|
|
if ($phone === '') {
|
|
@@ -3294,12 +3425,7 @@ class Procuremen extends Backend
|
|
|
Log::write('采购确认短信失败 phone=' . $phone . ' ' . $e->getMessage(), 'error');
|
|
Log::write('采购确认短信失败 phone=' . $phone . ' ' . $e->getMessage(), 'error');
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
-
|
|
|
|
|
- foreach ($selectedIds as $pid) {
|
|
|
|
|
- $dr = $this->purchaseOrderDetai($sid, $pid);
|
|
|
|
|
- if (!is_array($dr)) {
|
|
|
|
|
- continue;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ foreach ($winners as $dr) {
|
|
|
$cname = trim((string)($dr['company_name'] ?? ''));
|
|
$cname = trim((string)($dr['company_name'] ?? ''));
|
|
|
$ph = trim((string)($dr['phone'] ?? ''));
|
|
$ph = trim((string)($dr['phone'] ?? ''));
|
|
|
$sms = $this->renderNotifyTemplate('confirm_ok', array_merge($confirmNotifyVars, [
|
|
$sms = $this->renderNotifyTemplate('confirm_ok', array_merge($confirmNotifyVars, [
|
|
@@ -3307,13 +3433,9 @@ class Procuremen extends Backend
|
|
|
'contact_name' => $this->resolveCustomerContactName($ph, $cname),
|
|
'contact_name' => $this->resolveCustomerContactName($ph, $cname),
|
|
|
'phone' => $ph,
|
|
'phone' => $ph,
|
|
|
]));
|
|
]));
|
|
|
- $sendSmsSafe((string)($dr['phone'] ?? ''), $sms);
|
|
|
|
|
|
|
+ $sendSmsSafe($ph, $sms);
|
|
|
}
|
|
}
|
|
|
- foreach ($unselectedIds as $pid) {
|
|
|
|
|
- $dr = $this->purchaseOrderDetai($sid, $pid);
|
|
|
|
|
- if (!is_array($dr)) {
|
|
|
|
|
- continue;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ foreach ($losers as $dr) {
|
|
|
$cname = trim((string)($dr['company_name'] ?? ''));
|
|
$cname = trim((string)($dr['company_name'] ?? ''));
|
|
|
$ph = trim((string)($dr['phone'] ?? ''));
|
|
$ph = trim((string)($dr['phone'] ?? ''));
|
|
|
$sms = $this->renderNotifyTemplate('confirm_fail', array_merge($confirmNotifyVars, [
|
|
$sms = $this->renderNotifyTemplate('confirm_fail', array_merge($confirmNotifyVars, [
|
|
@@ -3321,31 +3443,22 @@ class Procuremen extends Backend
|
|
|
'contact_name' => $this->resolveCustomerContactName($ph, $cname),
|
|
'contact_name' => $this->resolveCustomerContactName($ph, $cname),
|
|
|
'phone' => $ph,
|
|
'phone' => $ph,
|
|
|
]));
|
|
]));
|
|
|
- $sendSmsSafe((string)($dr['phone'] ?? ''), $sms);
|
|
|
|
|
|
|
+ $sendSmsSafe($ph, $sms);
|
|
|
}
|
|
}
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- Log::write(sprintf(
|
|
|
|
|
- 'purchaseConfirmPick scydgy_id=%s purchase_order_id=%d selected_ids=%s unselected_ids=%s',
|
|
|
|
|
- $scydgyId,
|
|
|
|
|
- $purchaseOrderId,
|
|
|
|
|
- json_encode($selectedIds, JSON_UNESCAPED_UNICODE),
|
|
|
|
|
- json_encode($unselectedIds, JSON_UNESCAPED_UNICODE)
|
|
|
|
|
- ), 'notice');
|
|
|
|
|
-
|
|
|
|
|
- $pdfPublicPath = '';
|
|
|
|
|
- try {
|
|
|
|
|
- $pdfPublicPath = (string)$this->savePurchaseConfirmDetailPdf($sid, $poIdFinal);
|
|
|
|
|
- } catch (\Throwable $e) {
|
|
|
|
|
- Log::write('采购确认PDF异常: ' . $e->getMessage(), 'error');
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 短信去重键:优先手机号,否则公司名
|
|
|
|
|
+ */
|
|
|
|
|
+ protected function notifySupplierDedupeKey(array $detailRow): string
|
|
|
|
|
+ {
|
|
|
|
|
+ $ph = preg_replace('/\s+/', '', trim((string)($detailRow['phone'] ?? '')));
|
|
|
|
|
+ if ($ph !== '') {
|
|
|
|
|
+ return 'p:' . $ph;
|
|
|
}
|
|
}
|
|
|
|
|
+ $cn = trim((string)($detailRow['company_name'] ?? ''));
|
|
|
|
|
|
|
|
- return [
|
|
|
|
|
- 'scydgy_id' => $scydgyId,
|
|
|
|
|
- 'purchase_order_id' => $purchaseOrderId,
|
|
|
|
|
- 'selected_ids' => $selectedIds,
|
|
|
|
|
- 'unselected_ids' => $unselectedIds,
|
|
|
|
|
- 'purchase_confirm_pdf' => $pdfPublicPath,
|
|
|
|
|
- ];
|
|
|
|
|
|
|
+ return 'c:' . $cn;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -4848,17 +4961,38 @@ class Procuremen extends Backend
|
|
|
*
|
|
*
|
|
|
* @return array<string, string>
|
|
* @return array<string, string>
|
|
|
*/
|
|
*/
|
|
|
- protected function buildPurchaseConfirmNotifyVars(int $sid, int $fallbackDetailId = 0): array
|
|
|
|
|
|
|
+ protected function buildPurchaseConfirmNotifyVars(int $sid, int $fallbackDetailId = 0, ?array $bundle = null): array
|
|
|
{
|
|
{
|
|
|
- $po = null;
|
|
|
|
|
- try {
|
|
|
|
|
- $po = Db::table('purchase_order')->where('scydgy_id', $sid)->find();
|
|
|
|
|
- } catch (\Throwable $e) {
|
|
|
|
|
- $po = null;
|
|
|
|
|
|
|
+ if ($bundle === null || !is_array($bundle['merge_rows'] ?? null) || ($bundle['merge_rows'] ?? []) === []) {
|
|
|
|
|
+ $bundle = $this->loadOrderBundleForConfirmNotify($sid > 0 ? [$sid] : []);
|
|
|
}
|
|
}
|
|
|
- $ccydh = is_array($po) ? trim((string)($po['CCYDH'] ?? '')) : '';
|
|
|
|
|
- $cyjmc = is_array($po) ? trim((string)($po['CYJMC'] ?? '')) : '';
|
|
|
|
|
- if (($ccydh === '' || $cyjmc === '') && $fallbackDetailId > 0) {
|
|
|
|
|
|
|
+ $mergeRows = is_array($bundle['merge_rows'] ?? null) ? $bundle['merge_rows'] : [];
|
|
|
|
|
+ $pos = is_array($bundle['pos'] ?? null) ? $bundle['pos'] : [];
|
|
|
|
|
+ $ccydh = trim((string)($bundle['ccydh'] ?? ''));
|
|
|
|
|
+ $cyjmc = '';
|
|
|
|
|
+ foreach ($mergeRows as $mr) {
|
|
|
|
|
+ if (!is_array($mr)) {
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ if ($ccydh === '') {
|
|
|
|
|
+ $ccydh = trim((string)($mr['CCYDH'] ?? ''));
|
|
|
|
|
+ }
|
|
|
|
|
+ if ($cyjmc === '') {
|
|
|
|
|
+ $cyjmc = trim((string)($mr['CYJMC'] ?? ''));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if ($pos !== []) {
|
|
|
|
|
+ $firstPo = $pos[0];
|
|
|
|
|
+ if (is_array($firstPo)) {
|
|
|
|
|
+ if ($ccydh === '') {
|
|
|
|
|
+ $ccydh = trim((string)($firstPo['CCYDH'] ?? ''));
|
|
|
|
|
+ }
|
|
|
|
|
+ if ($cyjmc === '') {
|
|
|
|
|
+ $cyjmc = trim((string)($firstPo['CYJMC'] ?? ''));
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (($ccydh === '' || $cyjmc === '') && $fallbackDetailId > 0 && $sid > 0) {
|
|
|
$any = $this->purchaseOrderDetai($sid, $fallbackDetailId);
|
|
$any = $this->purchaseOrderDetai($sid, $fallbackDetailId);
|
|
|
if (is_array($any)) {
|
|
if (is_array($any)) {
|
|
|
if ($ccydh === '') {
|
|
if ($ccydh === '') {
|
|
@@ -4869,14 +5003,17 @@ class Procuremen extends Backend
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- $mergeRows = is_array($po) && $po !== [] ? [$po] : [];
|
|
|
|
|
$processPlain = $mergeRows !== [] ? $this->buildProcessLinesPlain($mergeRows) : '';
|
|
$processPlain = $mergeRows !== [] ? $this->buildProcessLinesPlain($mergeRows) : '';
|
|
|
$processLines = $this->buildPurchaseConfirmProcessLinesText($ccydh, $cyjmc, $processPlain);
|
|
$processLines = $this->buildPurchaseConfirmProcessLinesText($ccydh, $cyjmc, $processPlain);
|
|
|
|
|
+ $cgymc = '';
|
|
|
|
|
+ if (count($mergeRows) === 1 && is_array($mergeRows[0])) {
|
|
|
|
|
+ $cgymc = trim((string)($mergeRows[0]['CGYMC'] ?? ''));
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
return [
|
|
return [
|
|
|
'ccydh' => $ccydh,
|
|
'ccydh' => $ccydh,
|
|
|
'cyjmc' => $cyjmc,
|
|
'cyjmc' => $cyjmc,
|
|
|
- 'cgymc' => is_array($po) ? trim((string)($po['CGYMC'] ?? '')) : '',
|
|
|
|
|
|
|
+ 'cgymc' => $cgymc,
|
|
|
'process_lines' => $processLines,
|
|
'process_lines' => $processLines,
|
|
|
'process_lines_html' => '',
|
|
'process_lines_html' => '',
|
|
|
];
|
|
];
|