|
|
@@ -8704,7 +8704,7 @@ class Procuremen extends Backend
|
|
|
. "印件名称:{cyjmc}\n"
|
|
|
. "工序名称:{cgymc}\n"
|
|
|
. "本次数量:{this_quantity}\n"
|
|
|
- . "供应商:{supplier_name}\n"
|
|
|
+ . "供应商报价:\n{supplier_quotes}\n"
|
|
|
. "需求发起人:{cywyxm}\n";
|
|
|
try {
|
|
|
$row = Db::table('purchase_sms_template')
|
|
|
@@ -8716,10 +8716,14 @@ class Procuremen extends Backend
|
|
|
$now = date('Y-m-d H:i:s');
|
|
|
if (is_array($row) && $row !== []) {
|
|
|
$old = (string)($row['content'] ?? '');
|
|
|
- $needMigrate = (strpos($old, '需求编号:{ccydh}') !== false)
|
|
|
- || (strpos($old, '{supplier_name}') === false && strpos($old, '供应商:') === false);
|
|
|
+ // 仍用旧的「供应商:{supplier_name}」或没有报价占位符时,补上单价表格
|
|
|
+ $needMigrate = (strpos($old, '{supplier_quotes}') === false)
|
|
|
+ || (strpos($old, '供应商:{supplier_name}') !== false);
|
|
|
if ($needMigrate) {
|
|
|
$data = ['content' => $content];
|
|
|
+ if (trim((string)($row['title'] ?? '')) === '' || trim((string)($row['title'] ?? '')) === '询价通知') {
|
|
|
+ $data['title'] = '业务员询价通知';
|
|
|
+ }
|
|
|
try {
|
|
|
$cols = Db::query("SHOW COLUMNS FROM `purchase_sms_template` LIKE 'updatetime'");
|
|
|
if (!empty($cols)) {
|
|
|
@@ -8740,7 +8744,7 @@ class Procuremen extends Backend
|
|
|
try {
|
|
|
$data = [
|
|
|
'scene' => 'rfq_salesman_email',
|
|
|
- 'title' => '询价邮箱通知',
|
|
|
+ 'title' => '业务员询价通知',
|
|
|
'content' => $content,
|
|
|
'remark' => '查询询价-通知业务员邮箱;模版名称作邮件主题',
|
|
|
'status' => 1,
|
|
|
@@ -8772,6 +8776,84 @@ class Procuremen extends Backend
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 通知业务员邮件:供应商报价明细行(仅名称+单价)
|
|
|
+ *
|
|
|
+ * @return array<int, array{name:string,amount:string}>
|
|
|
+ */
|
|
|
+ protected function loadRfqSalesmanSupplierQuoteRows(int $sid, string $supplierRaw = ''): array
|
|
|
+ {
|
|
|
+ $list = [];
|
|
|
+ $seen = [];
|
|
|
+ try {
|
|
|
+ $rows = Db::table('purchase_order_detail')
|
|
|
+ ->where('scydgy_id', $sid)
|
|
|
+ ->field('company_name,amount')
|
|
|
+ ->order('id', 'asc')
|
|
|
+ ->select();
|
|
|
+ if (is_array($rows)) {
|
|
|
+ foreach ($rows as $r) {
|
|
|
+ if (!is_array($r)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $cn = trim((string)($r['company_name'] ?? ''));
|
|
|
+ if ($cn === '' || isset($seen[$cn])) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $seen[$cn] = true;
|
|
|
+ $amount = trim((string)($r['amount'] ?? ''));
|
|
|
+ $list[] = [
|
|
|
+ 'name' => $cn,
|
|
|
+ 'amount' => $amount !== '' ? $amount : '未报价',
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ }
|
|
|
+ if ($list === [] && $supplierRaw !== '') {
|
|
|
+ foreach ($this->splitRfqSalesmanNames($supplierRaw) as $cn) {
|
|
|
+ if ($cn === '' || isset($seen[$cn])) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $seen[$cn] = true;
|
|
|
+ $list[] = [
|
|
|
+ 'name' => $cn,
|
|
|
+ 'amount' => '未报价',
|
|
|
+ ];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return $list;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 通知业务员邮件:供应商报价 HTML 表格(名称+单价,不含时间)
|
|
|
+ */
|
|
|
+ protected function buildRfqSalesmanSupplierQuotesHtml(int $sid, string $supplierRaw = ''): string
|
|
|
+ {
|
|
|
+ $rows = $this->loadRfqSalesmanSupplierQuoteRows($sid, $supplierRaw);
|
|
|
+ if ($rows === []) {
|
|
|
+ return '<p style="margin:8px 0;color:#888;">暂无报价</p>';
|
|
|
+ }
|
|
|
+ $html = '<table cellpadding="0" cellspacing="0" border="1" '
|
|
|
+ . 'style="border-collapse:collapse;border-color:#ddd;width:100%;max-width:560px;font-size:14px;margin:8px 0;">'
|
|
|
+ . '<thead><tr style="background:#f5f5f5;">'
|
|
|
+ . '<th style="padding:8px 10px;text-align:center;width:56px;">序号</th>'
|
|
|
+ . '<th style="padding:8px 10px;text-align:left;">供应商名称</th>'
|
|
|
+ . '<th style="padding:8px 10px;text-align:center;width:100px;">单价</th>'
|
|
|
+ . '</tr></thead><tbody>';
|
|
|
+ foreach ($rows as $i => $row) {
|
|
|
+ $html .= '<tr>'
|
|
|
+ . '<td style="padding:8px 10px;text-align:center;">' . ($i + 1) . '</td>'
|
|
|
+ . '<td style="padding:8px 10px;">' . htmlspecialchars($row['name'], ENT_QUOTES, 'UTF-8') . '</td>'
|
|
|
+ . '<td style="padding:8px 10px;text-align:center;">' . htmlspecialchars($row['amount'], ENT_QUOTES, 'UTF-8') . '</td>'
|
|
|
+ . '</tr>';
|
|
|
+ }
|
|
|
+ $html .= '</tbody></table>';
|
|
|
+
|
|
|
+ return $html;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 询价多选字段:数组或字符串统一为顿号拼接
|
|
|
*
|
|
|
@@ -9617,12 +9699,16 @@ class Procuremen extends Backend
|
|
|
$ccydh = trim((string)($po['CCYDH'] ?? ''));
|
|
|
$cyjmc = trim((string)($po['CYJMC'] ?? ''));
|
|
|
$cgymc = trim((string)($po['CGYMC'] ?? ''));
|
|
|
- $qty = trim((string)($po['This_quantity'] ?? ''));
|
|
|
+ $cdw = trim((string)($po['CDW'] ?? ''));
|
|
|
+ $qty = trim((string)$this->resolveProcuremenThisQuantity($po));
|
|
|
+ $ceiling = trim((string)$this->resolveProcuremenCeilingPrice($po));
|
|
|
+ $mbz = trim((string)($po['MBZ'] ?? ''));
|
|
|
$cywyxm = trim((string)($po['cywyxm'] ?? ''));
|
|
|
$supplier = trim((string)($po['cGzzxMc'] ?? ''));
|
|
|
if ($supplier === '') {
|
|
|
$supplier = trim((string)($po['pick_company_name'] ?? ''));
|
|
|
}
|
|
|
+ $supplierQuotesHtml = $this->buildRfqSalesmanSupplierQuotesHtml($sid, $supplier);
|
|
|
try {
|
|
|
$mailSubjectTpl = $this->resolveProcuremenEmailSubject('rfq_salesman_email');
|
|
|
} catch (\Throwable $e) {
|
|
|
@@ -9634,21 +9720,29 @@ class Procuremen extends Backend
|
|
|
$toEmail = trim((string)($contact['email'] ?? ''));
|
|
|
$toName = trim((string)($contact['name'] ?? ''));
|
|
|
$notifyVars = [
|
|
|
- 'contact_name' => $toName,
|
|
|
- 'salesman_name' => $toName,
|
|
|
- 'company_name' => $toName,
|
|
|
- 'email' => $toEmail,
|
|
|
- 'ccydh' => $ccydh,
|
|
|
- 'cyjmc' => $cyjmc,
|
|
|
- 'cgymc' => $cgymc,
|
|
|
- 'this_quantity' => $qty,
|
|
|
- 'supplier_name' => $supplier,
|
|
|
- 'cywyxm' => $cywyxm,
|
|
|
+ 'contact_name' => $toName,
|
|
|
+ 'salesman_name' => $toName,
|
|
|
+ 'company_name' => $toName,
|
|
|
+ 'email' => $toEmail,
|
|
|
+ 'ccydh' => $ccydh,
|
|
|
+ 'cyjmc' => $cyjmc,
|
|
|
+ 'cgymc' => $cgymc,
|
|
|
+ 'cdw' => $cdw,
|
|
|
+ 'this_quantity' => $qty,
|
|
|
+ 'ceilingPrice' => $ceiling,
|
|
|
+ 'MBZ' => $mbz,
|
|
|
+ 'supplier_name' => $supplier,
|
|
|
+ // 占位符,转 HTML 后再替换成表格,避免被 htmlspecialchars 转义
|
|
|
+ 'supplier_quotes' => '__RFQ_SUPPLIER_QUOTES_TABLE__',
|
|
|
+ 'cywyxm' => $cywyxm,
|
|
|
];
|
|
|
try {
|
|
|
$mailPlain = $this->renderNotifyTemplate('rfq_salesman_email', $notifyVars);
|
|
|
$mailSubject = $mailSubjectTpl;
|
|
|
foreach ($notifyVars as $k => $v) {
|
|
|
+ if ($k === 'supplier_quotes') {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
$mailSubject = str_replace('{' . $k . '}', (string)$v, $mailSubject);
|
|
|
}
|
|
|
$mailSubject = preg_replace('/\{[a-zA-Z0-9_]+\}/', '', $mailSubject);
|
|
|
@@ -9657,10 +9751,12 @@ class Procuremen extends Backend
|
|
|
$mailSubject = '协助采购询价通知' . ($ccydh !== '' ? ' - ' . $ccydh : '');
|
|
|
}
|
|
|
$mailBody = $this->plainTextToHtmlEmailBody($mailPlain);
|
|
|
+ $mailBody = str_replace('__RFQ_SUPPLIER_QUOTES_TABLE__', $supplierQuotesHtml, $mailBody);
|
|
|
+ $mailPlainForLog = str_replace('__RFQ_SUPPLIER_QUOTES_TABLE__', strip_tags(str_replace(['</tr>', '</p>'], "\n", $supplierQuotesHtml)), $mailPlain);
|
|
|
$bundle = [
|
|
|
'company_name' => $toName,
|
|
|
'email' => $toEmail,
|
|
|
- 'mail_plain' => $mailPlain,
|
|
|
+ 'mail_plain' => $mailPlainForLog,
|
|
|
'mail_body' => $mailBody,
|
|
|
'ccydh' => $ccydh,
|
|
|
'email_log_scene' => 'rfq_salesman',
|
|
|
@@ -9727,6 +9823,50 @@ class Procuremen extends Backend
|
|
|
$supplierRaw = trim((string)($po['pick_company_name'] ?? ''));
|
|
|
}
|
|
|
$names = $this->splitRfqSalesmanNames($supplierRaw);
|
|
|
+
|
|
|
+ // 已成功发过询价邮件的供应商(含历史 pick_issue 场景)
|
|
|
+ $notifiedMap = [];
|
|
|
+ try {
|
|
|
+ $this->ensurePurchaseEmailSendLogTableOnce();
|
|
|
+ $logRows = Db::table('purchase_email_send_log')
|
|
|
+ ->where('scydgy_id', $sid)
|
|
|
+ ->where('status', 1)
|
|
|
+ ->where('scene', 'in', ['rfq_supplier', 'pick_issue'])
|
|
|
+ ->field('company_name')
|
|
|
+ ->select();
|
|
|
+ if (is_array($logRows)) {
|
|
|
+ foreach ($logRows as $lr) {
|
|
|
+ if (!is_array($lr)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $cn = trim((string)($lr['company_name'] ?? ''));
|
|
|
+ if ($cn !== '') {
|
|
|
+ $notifiedMap[$cn] = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ }
|
|
|
+ // 兼容:明细已生成(曾下发)也视为已通知
|
|
|
+ try {
|
|
|
+ $detRows = Db::table('purchase_order_detail')
|
|
|
+ ->where('scydgy_id', $sid)
|
|
|
+ ->field('company_name')
|
|
|
+ ->select();
|
|
|
+ if (is_array($detRows)) {
|
|
|
+ foreach ($detRows as $dr) {
|
|
|
+ if (!is_array($dr)) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ $cn = trim((string)($dr['company_name'] ?? ''));
|
|
|
+ if ($cn !== '') {
|
|
|
+ $notifiedMap[$cn] = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ }
|
|
|
+
|
|
|
$list = [];
|
|
|
foreach ($names as $name) {
|
|
|
// 展示用:无邮箱/手机也返回档案信息(与供应商分组一致)
|
|
|
@@ -9735,13 +9875,16 @@ class Procuremen extends Backend
|
|
|
$phone = is_array($contact) ? trim((string)($contact['phone'] ?? '')) : '';
|
|
|
$username = is_array($contact) ? trim((string)($contact['username'] ?? '')) : '';
|
|
|
$okEmail = ($email !== '' && filter_var($email, FILTER_VALIDATE_EMAIL));
|
|
|
+ $notified = !empty($notifiedMap[$name]) ? 1 : 0;
|
|
|
$list[] = [
|
|
|
- 'name' => $name,
|
|
|
- 'username' => $username,
|
|
|
- 'email' => $email,
|
|
|
- 'phone' => $phone,
|
|
|
- 'can_notify' => $okEmail ? 1 : 0,
|
|
|
- 'found' => is_array($contact) ? 1 : 0,
|
|
|
+ 'name' => $name,
|
|
|
+ 'username' => $username,
|
|
|
+ 'email' => $email,
|
|
|
+ 'phone' => $phone,
|
|
|
+ 'can_notify' => $okEmail ? 1 : 0,
|
|
|
+ 'found' => is_array($contact) ? 1 : 0,
|
|
|
+ 'notified' => $notified,
|
|
|
+ 'notify_status_text' => $notified ? '已通知' : '未通知',
|
|
|
];
|
|
|
}
|
|
|
|