ProcuremenSchema.php 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. <?php
  2. namespace app\common\library;
  3. use think\Cache;
  4. use think\Config;
  5. use think\Db;
  6. use think\Log;
  7. /**
  8. * 协助采购 / 手机端报价相关表结构保障:
  9. * - 表不存在 → CREATE(完整字段)
  10. * - 表存在但缺列 → ALTER ADD(静默,不抛「字段不存在」给业务)
  11. */
  12. class ProcuremenSchema
  13. {
  14. public const CACHE_KEY = 'procuremen_quote_schema_ok_v1';
  15. /** @var bool */
  16. protected static $done = false;
  17. public static function ensureAll(): void
  18. {
  19. if (self::$done) {
  20. return;
  21. }
  22. self::$done = true;
  23. try {
  24. if (Cache::get(self::CACHE_KEY)) {
  25. return;
  26. }
  27. } catch (\Throwable $e) {
  28. }
  29. $changed = false;
  30. try {
  31. $changed = self::ensurePurchaseOrderTable() || $changed;
  32. $changed = self::ensurePurchaseOrderDetailTable() || $changed;
  33. $changed = self::ensurePurchaseOrderOperLogTable() || $changed;
  34. $changed = self::ensurePurchaseOrderBidOpenTable() || $changed;
  35. $changed = self::ensurePurchaseOrderInboundScoreTable() || $changed;
  36. $changed = self::ensurePurchaseEmailSendLogTable() || $changed;
  37. $changed = self::ensurePurchaseSmsTemplateTable() || $changed;
  38. try {
  39. ProcuremenSupplierScore::ensureSchema();
  40. } catch (\Throwable $e) {
  41. Log::write('ProcuremenSchema score: ' . $e->getMessage(), 'error');
  42. }
  43. if ($changed) {
  44. self::clearTableFieldsCache([
  45. 'purchase_order',
  46. 'purchase_order_detail',
  47. 'purchase_order_oper_log',
  48. 'purchase_order_bid_open',
  49. 'purchase_order_inbound_score',
  50. 'purchase_email_send_log',
  51. 'purchase_sms_template',
  52. ]);
  53. }
  54. try {
  55. Cache::set(self::CACHE_KEY, 1, 86400);
  56. } catch (\Throwable $e) {
  57. }
  58. } catch (\Throwable $e) {
  59. Log::write('ProcuremenSchema::ensureAll: ' . $e->getMessage(), 'error');
  60. }
  61. }
  62. /**
  63. * 强制下次请求重新探测(改库后可清 runtime cache 或调此方法)
  64. */
  65. public static function invalidateCache(): void
  66. {
  67. self::$done = false;
  68. try {
  69. Cache::rm(self::CACHE_KEY);
  70. } catch (\Throwable $e) {
  71. }
  72. }
  73. protected static function tableExists(string $table): bool
  74. {
  75. try {
  76. Db::query('SELECT 1 FROM `' . str_replace('`', '', $table) . '` LIMIT 1');
  77. return true;
  78. } catch (\Throwable $e) {
  79. return false;
  80. }
  81. }
  82. /**
  83. * @param array<string, string> $columns col => ADD COLUMN ... DDL fragment (without ADD COLUMN prefix ok if starts with ADD)
  84. */
  85. protected static function ensureColumns(string $table, array $columns): bool
  86. {
  87. $changed = false;
  88. $table = str_replace('`', '', $table);
  89. foreach ($columns as $col => $ddl) {
  90. $col = str_replace('`', '', (string)$col);
  91. if ($col === '') {
  92. continue;
  93. }
  94. try {
  95. $exists = Db::query("SHOW COLUMNS FROM `{$table}` LIKE '{$col}'");
  96. if (is_array($exists) && $exists !== []) {
  97. continue;
  98. }
  99. $ddl = trim($ddl);
  100. if (stripos($ddl, 'ADD ') !== 0) {
  101. $ddl = 'ADD COLUMN ' . $ddl;
  102. }
  103. Db::execute("ALTER TABLE `{$table}` {$ddl}");
  104. $changed = true;
  105. } catch (\Throwable $e) {
  106. Log::write("ProcuremenSchema {$table}.{$col}: " . $e->getMessage(), 'error');
  107. }
  108. }
  109. return $changed;
  110. }
  111. /**
  112. * @param string[] $tables
  113. */
  114. protected static function clearTableFieldsCache(array $tables): void
  115. {
  116. $db = '';
  117. try {
  118. $db = (string)Config::get('database.database');
  119. } catch (\Throwable $e) {
  120. }
  121. try {
  122. $ref = new \ReflectionProperty(\think\db\Query::class, 'info');
  123. $ref->setAccessible(true);
  124. $info = $ref->getValue();
  125. if (is_array($info)) {
  126. foreach ($tables as $t) {
  127. $key = ($db !== '' ? $db . '.' : '') . $t;
  128. unset($info[$key], $info[$t]);
  129. }
  130. $ref->setValue(null, $info);
  131. }
  132. } catch (\Throwable $e) {
  133. }
  134. if ($db === '') {
  135. return;
  136. }
  137. foreach ($tables as $t) {
  138. $schemaFile = RUNTIME_PATH . 'schema' . DIRECTORY_SEPARATOR . $db . '.' . $t . '.php';
  139. if (is_file($schemaFile)) {
  140. @unlink($schemaFile);
  141. }
  142. }
  143. }
  144. protected static function ensurePurchaseOrderTable(): bool
  145. {
  146. $changed = false;
  147. if (!self::tableExists('purchase_order')) {
  148. try {
  149. Db::execute("CREATE TABLE IF NOT EXISTS `purchase_order` (
  150. `id` int NOT NULL AUTO_INCREMENT,
  151. `scydgy_id` int DEFAULT NULL COMMENT '工序行ID(手工询价为负数)',
  152. `CCYDH` varchar(255) DEFAULT NULL COMMENT '订单号',
  153. `CYJMC` varchar(255) DEFAULT NULL COMMENT '印件名称',
  154. `CDXMC` varchar(255) DEFAULT NULL,
  155. `CGYBH` varchar(255) DEFAULT NULL,
  156. `CCLBMMC` varchar(255) DEFAULT NULL COMMENT '需求部门',
  157. `CGYMC` varchar(255) DEFAULT NULL COMMENT '工序名称',
  158. `CDW` varchar(255) DEFAULT NULL COMMENT '单位',
  159. `czlyq` varchar(64) NOT NULL DEFAULT '' COMMENT '类型',
  160. `NGZL` varchar(255) DEFAULT NULL COMMENT '工作量',
  161. `This_quantity` varchar(255) DEFAULT NULL COMMENT '本次数量',
  162. `ceilingPrice` varchar(255) DEFAULT NULL COMMENT '最高限价',
  163. `CDF` varchar(255) DEFAULT NULL COMMENT '订法',
  164. `cGzzxMc` varchar(255) DEFAULT NULL COMMENT '外厂单位',
  165. `MBZ` varchar(255) DEFAULT NULL COMMENT '备注',
  166. `bwjg` varchar(255) DEFAULT NULL,
  167. `iStatus` varchar(255) DEFAULT NULL,
  168. `dStamp` varchar(255) DEFAULT NULL,
  169. `dputrecord` varchar(255) DEFAULT NULL,
  170. `cywyxm` varchar(255) DEFAULT NULL COMMENT '业务员/需求发起人',
  171. `notify_salesman` varchar(500) NOT NULL DEFAULT '' COMMENT '通知业务员(可多选)',
  172. `rfq_salesman_notified` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '手工询价已通知业务员0否1是',
  173. `rfq_salesman_notify_time` datetime DEFAULT NULL COMMENT '手工询价通知业务员时间',
  174. `status` varchar(255) DEFAULT NULL COMMENT '空=未完结、0=进行中、1=已完结',
  175. `createtime` varchar(255) DEFAULT NULL COMMENT '录入时间',
  176. `pdf_url` varchar(255) DEFAULT NULL COMMENT 'pdf路径',
  177. `sys_rq` varchar(255) DEFAULT NULL COMMENT '招标截止日期',
  178. `delivery_deadline` date DEFAULT NULL COMMENT '交货截止日期',
  179. `wflow_status` varchar(255) DEFAULT NULL COMMENT '流程状态',
  180. `pick_company_name` varchar(255) DEFAULT NULL COMMENT '中标/选定供应商',
  181. `manual_pick` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '1=自选供应商(免开标)',
  182. `manual_pick_reason` varchar(500) NOT NULL DEFAULT '' COMMENT '自选供应商说明',
  183. `pick_time` datetime DEFAULT NULL COMMENT '选定时间',
  184. `score_rule_id` int unsigned NOT NULL DEFAULT 0 COMMENT '评分规则ID',
  185. `score_rule_name` varchar(100) NOT NULL DEFAULT '' COMMENT '规则名称快照',
  186. `score_quality_weight` int unsigned NOT NULL DEFAULT 0 COMMENT '质量权重快照%',
  187. `score_price_weight` int unsigned NOT NULL DEFAULT 0 COMMENT '价格权重快照%',
  188. `score_lead_weight` int unsigned NOT NULL DEFAULT 0 COMMENT '交货权重快照%',
  189. `mod_rq` varchar(255) DEFAULT NULL COMMENT '软删除日期',
  190. PRIMARY KEY (`id`),
  191. KEY `idx_scydgy_id` (`scydgy_id`),
  192. KEY `idx_CCYDH` (`CCYDH`(64)),
  193. KEY `idx_wflow_status` (`wflow_status`(32))
  194. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='协助采购订单(工序行)'");
  195. $changed = true;
  196. } catch (\Throwable $e) {
  197. Log::write('ProcuremenSchema create purchase_order: ' . $e->getMessage(), 'error');
  198. }
  199. }
  200. $changed = self::ensureColumns('purchase_order', [
  201. 'czlyq' => "`czlyq` varchar(64) NOT NULL DEFAULT '' COMMENT '类型'",
  202. 'notify_salesman' => "`notify_salesman` varchar(500) NOT NULL DEFAULT '' COMMENT '通知业务员(可多选)'",
  203. 'rfq_salesman_notified' => "`rfq_salesman_notified` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '手工询价已通知业务员0否1是'",
  204. 'rfq_salesman_notify_time' => "`rfq_salesman_notify_time` datetime DEFAULT NULL COMMENT '手工询价通知业务员时间'",
  205. 'manual_pick' => "`manual_pick` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '1=自选供应商(免开标)'",
  206. 'manual_pick_reason' => "`manual_pick_reason` varchar(500) NOT NULL DEFAULT '' COMMENT '自选供应商说明'",
  207. 'pick_time' => "`pick_time` datetime DEFAULT NULL COMMENT '选定时间'",
  208. 'delivery_deadline' => "`delivery_deadline` date DEFAULT NULL COMMENT '交货截止日期'",
  209. 'score_rule_id' => "`score_rule_id` int unsigned NOT NULL DEFAULT 0 COMMENT '评分规则ID'",
  210. 'score_rule_name' => "`score_rule_name` varchar(100) NOT NULL DEFAULT '' COMMENT '规则名称快照'",
  211. 'score_quality_weight' => "`score_quality_weight` int unsigned NOT NULL DEFAULT 0 COMMENT '质量权重快照%'",
  212. 'score_price_weight' => "`score_price_weight` int unsigned NOT NULL DEFAULT 0 COMMENT '价格权重快照%'",
  213. 'score_lead_weight' => "`score_lead_weight` int unsigned NOT NULL DEFAULT 0 COMMENT '交货权重快照%'",
  214. 'This_quantity' => "`This_quantity` varchar(255) DEFAULT NULL COMMENT '本次数量'",
  215. 'ceilingPrice' => "`ceilingPrice` varchar(255) DEFAULT NULL COMMENT '最高限价'",
  216. 'pick_company_name' => "`pick_company_name` varchar(255) DEFAULT NULL COMMENT '中标/选定供应商'",
  217. 'wflow_status' => "`wflow_status` varchar(255) DEFAULT NULL COMMENT '流程状态'",
  218. 'mod_rq' => "`mod_rq` varchar(255) DEFAULT NULL COMMENT '软删除日期'",
  219. 'cywyxm' => "`cywyxm` varchar(255) DEFAULT NULL COMMENT '业务员/需求发起人'",
  220. 'CCLBMMC' => "`CCLBMMC` varchar(255) DEFAULT NULL COMMENT '需求部门'",
  221. 'MBZ' => "`MBZ` varchar(255) DEFAULT NULL COMMENT '备注'",
  222. 'createtime' => "`createtime` varchar(255) DEFAULT NULL COMMENT '录入时间'",
  223. 'pdf_url' => "`pdf_url` varchar(255) DEFAULT NULL COMMENT 'pdf路径'",
  224. 'sys_rq' => "`sys_rq` varchar(255) DEFAULT NULL COMMENT '招标截止日期'",
  225. ]) || $changed;
  226. return $changed;
  227. }
  228. protected static function ensurePurchaseOrderDetailTable(): bool
  229. {
  230. $changed = false;
  231. if (!self::tableExists('purchase_order_detail')) {
  232. try {
  233. Db::execute("CREATE TABLE IF NOT EXISTS `purchase_order_detail` (
  234. `id` int NOT NULL AUTO_INCREMENT,
  235. `scydgy_id` int DEFAULT NULL COMMENT '工序行ID',
  236. `CCYDH` varchar(255) DEFAULT NULL COMMENT '订单号',
  237. `CYJMC` varchar(255) DEFAULT NULL COMMENT '印件名称',
  238. `CGYMC` varchar(255) DEFAULT NULL COMMENT '工序名称',
  239. `amount` varchar(255) DEFAULT NULL COMMENT '单价/金额',
  240. `delivery` datetime DEFAULT NULL COMMENT '交货日期',
  241. `delivery_createtime` datetime DEFAULT NULL COMMENT '报价提交时间',
  242. `lead_days` int unsigned DEFAULT NULL COMMENT '预估工期(天)',
  243. `company_name` varchar(255) DEFAULT NULL COMMENT '供应商名称',
  244. `username` varchar(128) DEFAULT NULL COMMENT '供应商账号',
  245. `email` varchar(255) DEFAULT NULL COMMENT '邮箱',
  246. `phone` varchar(255) DEFAULT NULL COMMENT '手机号',
  247. `createtime` datetime DEFAULT NULL COMMENT '下发时间',
  248. `status` varchar(255) DEFAULT NULL COMMENT '数值状态',
  249. `status_name` varchar(255) DEFAULT NULL COMMENT '状态名',
  250. `remark` varchar(500) DEFAULT NULL COMMENT '供应商整单备注',
  251. PRIMARY KEY (`id`),
  252. KEY `idx_scydgy_id` (`scydgy_id`),
  253. KEY `idx_CCYDH` (`CCYDH`(64)),
  254. KEY `idx_company_name` (`company_name`(64)),
  255. KEY `idx_status_name` (`status_name`(32))
  256. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='协助采购报价明细'");
  257. $changed = true;
  258. } catch (\Throwable $e) {
  259. Log::write('ProcuremenSchema create purchase_order_detail: ' . $e->getMessage(), 'error');
  260. }
  261. }
  262. $changed = self::ensureColumns('purchase_order_detail', [
  263. 'amount' => "`amount` varchar(255) DEFAULT NULL COMMENT '单价/金额'",
  264. 'delivery' => "`delivery` datetime DEFAULT NULL COMMENT '交货日期'",
  265. 'delivery_createtime' => "`delivery_createtime` datetime DEFAULT NULL COMMENT '报价提交时间'",
  266. 'lead_days' => "`lead_days` int unsigned DEFAULT NULL COMMENT '预估工期(天)'",
  267. 'company_name' => "`company_name` varchar(255) DEFAULT NULL COMMENT '供应商名称'",
  268. 'username' => "`username` varchar(128) DEFAULT NULL COMMENT '供应商账号'",
  269. 'email' => "`email` varchar(255) DEFAULT NULL COMMENT '邮箱'",
  270. 'phone' => "`phone` varchar(255) DEFAULT NULL COMMENT '手机号'",
  271. 'status' => "`status` varchar(255) DEFAULT NULL COMMENT '数值状态'",
  272. 'status_name' => "`status_name` varchar(255) DEFAULT NULL COMMENT '状态名'",
  273. 'remark' => "`remark` varchar(500) DEFAULT NULL COMMENT '供应商整单备注'",
  274. 'CYJMC' => "`CYJMC` varchar(255) DEFAULT NULL COMMENT '印件名称'",
  275. 'CGYMC' => "`CGYMC` varchar(255) DEFAULT NULL COMMENT '工序名称'",
  276. 'CCYDH' => "`CCYDH` varchar(255) DEFAULT NULL COMMENT '订单号'",
  277. 'scydgy_id' => "`scydgy_id` int DEFAULT NULL COMMENT '工序行ID'",
  278. 'createtime' => "`createtime` datetime DEFAULT NULL COMMENT '下发时间'",
  279. ]) || $changed;
  280. return $changed;
  281. }
  282. protected static function ensurePurchaseOrderOperLogTable(): bool
  283. {
  284. if (self::tableExists('purchase_order_oper_log')) {
  285. return self::ensureColumns('purchase_order_oper_log', [
  286. 'scydgy_id' => "`scydgy_id` int NOT NULL DEFAULT 0 COMMENT '工序行ID'",
  287. 'purchase_order_id' => "`purchase_order_id` int unsigned DEFAULT NULL COMMENT 'purchase_order.id'",
  288. 'admin_id' => "`admin_id` int unsigned DEFAULT NULL COMMENT '操作人'",
  289. 'admin_name' => "`admin_name` varchar(64) NOT NULL DEFAULT '' COMMENT '操作人快照'",
  290. 'action' => "`action` varchar(64) NOT NULL DEFAULT '' COMMENT '动作码'",
  291. 'content' => "`content` varchar(1000) NOT NULL DEFAULT '' COMMENT '描述'",
  292. 'createtime' => "`createtime` int unsigned NOT NULL DEFAULT 0 COMMENT 'Unix时间戳'",
  293. ]);
  294. }
  295. try {
  296. Db::execute("CREATE TABLE IF NOT EXISTS `purchase_order_oper_log` (
  297. `id` int unsigned NOT NULL AUTO_INCREMENT,
  298. `scydgy_id` int NOT NULL DEFAULT 0 COMMENT '工序行 scydgy.ID',
  299. `purchase_order_id` int unsigned DEFAULT NULL COMMENT 'purchase_order.id',
  300. `admin_id` int unsigned DEFAULT NULL COMMENT '操作人 admin.id',
  301. `admin_name` varchar(64) NOT NULL DEFAULT '' COMMENT '操作人昵称/账号快照',
  302. `action` varchar(64) NOT NULL DEFAULT '' COMMENT '动作码',
  303. `content` varchar(1000) NOT NULL DEFAULT '' COMMENT '中文描述',
  304. `createtime` int unsigned NOT NULL DEFAULT 0 COMMENT 'Unix 时间戳',
  305. PRIMARY KEY (`id`),
  306. KEY `idx_scydgy_ct` (`scydgy_id`,`createtime`)
  307. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='协助采购操作日志'");
  308. return true;
  309. } catch (\Throwable $e) {
  310. Log::write('ProcuremenSchema create purchase_order_oper_log: ' . $e->getMessage(), 'error');
  311. return false;
  312. }
  313. }
  314. protected static function ensurePurchaseOrderBidOpenTable(): bool
  315. {
  316. if (self::tableExists('purchase_order_bid_open')) {
  317. return false;
  318. }
  319. try {
  320. Db::execute("CREATE TABLE IF NOT EXISTS `purchase_order_bid_open` (
  321. `id` int unsigned NOT NULL AUTO_INCREMENT,
  322. `ccydh` varchar(64) NOT NULL DEFAULT '' COMMENT '订单号',
  323. `verifier1_id` int unsigned NOT NULL DEFAULT 0,
  324. `verifier1_name` varchar(64) NOT NULL DEFAULT '',
  325. `verifier2_id` int unsigned NOT NULL DEFAULT 0,
  326. `verifier2_name` varchar(64) NOT NULL DEFAULT '',
  327. `operator_id` int unsigned NOT NULL DEFAULT 0,
  328. `operator_name` varchar(64) NOT NULL DEFAULT '',
  329. `createtime` datetime DEFAULT NULL,
  330. PRIMARY KEY (`id`),
  331. UNIQUE KEY `uk_ccydh` (`ccydh`)
  332. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='开标双重验证'");
  333. return true;
  334. } catch (\Throwable $e) {
  335. Log::write('ProcuremenSchema create purchase_order_bid_open: ' . $e->getMessage(), 'error');
  336. return false;
  337. }
  338. }
  339. protected static function ensurePurchaseOrderInboundScoreTable(): bool
  340. {
  341. $changed = false;
  342. if (!self::tableExists('purchase_order_inbound_score')) {
  343. try {
  344. Db::execute("CREATE TABLE IF NOT EXISTS `purchase_order_inbound_score` (
  345. `id` int unsigned NOT NULL AUTO_INCREMENT,
  346. `scydgy_id` int NOT NULL DEFAULT 0 COMMENT '工序ID',
  347. `purchase_order_id` int unsigned NOT NULL DEFAULT 0 COMMENT 'purchase_order.id',
  348. `ccydh` varchar(64) NOT NULL DEFAULT '' COMMENT '订单号',
  349. `cyjmc` varchar(255) NOT NULL DEFAULT '' COMMENT '印件名称',
  350. `cgymc` varchar(255) NOT NULL DEFAULT '' COMMENT '工序名称',
  351. `company_name` varchar(255) NOT NULL DEFAULT '' COMMENT '中标供应商',
  352. `result` varchar(16) NOT NULL DEFAULT '' COMMENT '合格/不合格',
  353. `delivery_status` varchar(16) NOT NULL DEFAULT '' COMMENT '交货情况 准时/滞后',
  354. `delivery_date` date DEFAULT NULL COMMENT '交货日期',
  355. `customer_complaint` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '客户是否投诉 1=是',
  356. `complaint_remark` varchar(500) NOT NULL DEFAULT '' COMMENT '投诉说明',
  357. `order_interrupt` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '订单是否中断 1=是',
  358. `admin_id` int unsigned NOT NULL DEFAULT 0,
  359. `admin_name` varchar(64) NOT NULL DEFAULT '',
  360. `remark` varchar(500) NOT NULL DEFAULT '',
  361. `createtime` datetime DEFAULT NULL,
  362. `updatetime` datetime DEFAULT NULL,
  363. PRIMARY KEY (`id`),
  364. UNIQUE KEY `uk_scydgy_id` (`scydgy_id`),
  365. KEY `idx_ccydh` (`ccydh`),
  366. KEY `idx_result` (`result`),
  367. KEY `idx_updatetime` (`updatetime`)
  368. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='质量/交货评分'");
  369. $changed = true;
  370. } catch (\Throwable $e) {
  371. Log::write('ProcuremenSchema create inbound_score: ' . $e->getMessage(), 'error');
  372. }
  373. }
  374. return self::ensureColumns('purchase_order_inbound_score', [
  375. 'delivery_status' => "`delivery_status` varchar(16) NOT NULL DEFAULT '' COMMENT '交货情况 准时/滞后'",
  376. 'delivery_date' => "`delivery_date` date DEFAULT NULL COMMENT '交货日期'",
  377. 'customer_complaint' => "`customer_complaint` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '客户是否投诉 1=是'",
  378. 'complaint_remark' => "`complaint_remark` varchar(500) NOT NULL DEFAULT '' COMMENT '投诉说明'",
  379. 'order_interrupt' => "`order_interrupt` tinyint unsigned NOT NULL DEFAULT 0 COMMENT '订单是否中断 1=是'",
  380. 'result' => "`result` varchar(16) NOT NULL DEFAULT '' COMMENT '合格/不合格'",
  381. 'company_name' => "`company_name` varchar(255) NOT NULL DEFAULT '' COMMENT '中标供应商'",
  382. 'ccydh' => "`ccydh` varchar(64) NOT NULL DEFAULT '' COMMENT '订单号'",
  383. 'scydgy_id' => "`scydgy_id` int NOT NULL DEFAULT 0 COMMENT '工序ID'",
  384. ]) || $changed;
  385. }
  386. protected static function ensurePurchaseEmailSendLogTable(): bool
  387. {
  388. if (self::tableExists('purchase_email_send_log')) {
  389. return false;
  390. }
  391. try {
  392. Db::execute("CREATE TABLE IF NOT EXISTS `purchase_email_send_log` (
  393. `id` int unsigned NOT NULL AUTO_INCREMENT,
  394. `from_email` varchar(128) NOT NULL DEFAULT '' COMMENT '发件邮箱',
  395. `to_email` varchar(128) NOT NULL DEFAULT '' COMMENT '收件邮箱',
  396. `send_time` datetime DEFAULT NULL COMMENT '发送时间',
  397. `scene` varchar(32) NOT NULL DEFAULT '' COMMENT '场景',
  398. `ccydh` varchar(64) NOT NULL DEFAULT '' COMMENT '订单号',
  399. `company_name` varchar(128) NOT NULL DEFAULT '' COMMENT '供应商名称',
  400. `mail_subject` varchar(255) NOT NULL DEFAULT '' COMMENT '邮件主题',
  401. `status` tinyint(1) NOT NULL DEFAULT 1 COMMENT '1成功 0失败',
  402. `fail_reason` varchar(500) NOT NULL DEFAULT '' COMMENT '失败原因',
  403. `admin_id` int unsigned NOT NULL DEFAULT 0 COMMENT '操作人ID',
  404. `admin_name` varchar(64) NOT NULL DEFAULT '' COMMENT '操作人',
  405. `scydgy_id` int NOT NULL DEFAULT 0 COMMENT '工序行ID',
  406. `purchase_order_id` int unsigned NOT NULL DEFAULT 0 COMMENT 'purchase_order.id',
  407. `createtime` datetime DEFAULT NULL COMMENT '记录创建时间',
  408. PRIMARY KEY (`id`),
  409. KEY `idx_send_time` (`send_time`),
  410. KEY `idx_to_email` (`to_email`),
  411. KEY `idx_ccydh` (`ccydh`),
  412. KEY `idx_scene` (`scene`)
  413. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='协助采购邮件发送日志'");
  414. return true;
  415. } catch (\Throwable $e) {
  416. Log::write('ProcuremenSchema create email_send_log: ' . $e->getMessage(), 'error');
  417. return false;
  418. }
  419. }
  420. protected static function ensurePurchaseSmsTemplateTable(): bool
  421. {
  422. if (self::tableExists('purchase_sms_template')) {
  423. return self::ensureColumns('purchase_sms_template', [
  424. 'scene' => "`scene` varchar(32) DEFAULT NULL COMMENT '场景码'",
  425. 'title' => "`title` varchar(100) DEFAULT '' COMMENT '模版名称'",
  426. 'content' => "`content` text COMMENT '正文'",
  427. 'remark' => "`remark` varchar(255) DEFAULT '' COMMENT '备注'",
  428. 'status' => "`status` varchar(30) DEFAULT 'normal'",
  429. ]);
  430. }
  431. try {
  432. Db::execute("CREATE TABLE IF NOT EXISTS `purchase_sms_template` (
  433. `id` int unsigned NOT NULL AUTO_INCREMENT,
  434. `scene` varchar(32) DEFAULT NULL COMMENT '场景码',
  435. `title` varchar(100) DEFAULT '' COMMENT '模版名称',
  436. `content` text COMMENT '正文',
  437. `remark` varchar(255) DEFAULT '' COMMENT '备注',
  438. `status` varchar(30) DEFAULT 'normal',
  439. `createtime` datetime DEFAULT NULL,
  440. `updatetime` datetime DEFAULT NULL,
  441. PRIMARY KEY (`id`),
  442. UNIQUE KEY `uk_scene` (`scene`)
  443. ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='协助采购短信/邮件模版'");
  444. return true;
  445. } catch (\Throwable $e) {
  446. Log::write('ProcuremenSchema create sms_template: ' . $e->getMessage(), 'error');
  447. return false;
  448. }
  449. }
  450. }