|
|
@@ -2,11 +2,13 @@
|
|
|
|
|
|
namespace App\Console\Commands;
|
|
|
|
|
|
-use App\Model\DDEmployee;
|
|
|
-use App\Model\Record;
|
|
|
-use App\Service\U8DatabaseServerService;
|
|
|
+use App\Jobs\ProcessWMSDataJob;
|
|
|
+use App\Model\SyncTempRecord;
|
|
|
+use App\Service\U8ThirtyPartyDatabaseServerService;
|
|
|
use Illuminate\Console\Command;
|
|
|
+use Illuminate\Support\Facades\DB;
|
|
|
use Illuminate\Support\Facades\Log;
|
|
|
+use Illuminate\Support\Facades\Redis;
|
|
|
|
|
|
class U8Settle extends Command
|
|
|
{
|
|
|
@@ -34,112 +36,298 @@ class U8Settle extends Command
|
|
|
parent::__construct();
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Execute the console command.
|
|
|
- *
|
|
|
- * @return mixed
|
|
|
- */
|
|
|
public function handle()
|
|
|
{
|
|
|
- echo '任务--------start---------------';
|
|
|
- $this->syncApprovedRecords();
|
|
|
- echo '任务结束--------end---------------';
|
|
|
+ try {
|
|
|
+ $this->settle();
|
|
|
+ }catch (\Exception $exception){
|
|
|
+ Log::channel('apiLog')->info('异常', ['msg' => $exception->getMessage() . '|' . $exception->getLine()]);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- public function syncApprovedRecords()
|
|
|
- {
|
|
|
- try {
|
|
|
- $databases = [
|
|
|
- "UFDATA_200_2021",
|
|
|
- "UFDATA_002_2021",
|
|
|
- "UFDATA_999_2021",
|
|
|
- ];
|
|
|
-
|
|
|
- //初始化连接池
|
|
|
- $connections = [];
|
|
|
- $error = true;
|
|
|
- foreach ($databases as $db) {
|
|
|
- if(! $error) continue;
|
|
|
- $service = new U8DatabaseServerService(['zt_database' => $db]);
|
|
|
- if ($service->error) {
|
|
|
- Log::channel('apiLog')->info('SQLServer连接失败', [
|
|
|
- "database" => $db,
|
|
|
- "error" => $service->error,
|
|
|
- ]);
|
|
|
- $error = false;
|
|
|
- $connections[$db] = null; // 标记连接失败
|
|
|
- } else {
|
|
|
- $connections[$db] = $service;
|
|
|
- }
|
|
|
- }
|
|
|
- if(! $error ) return;
|
|
|
-
|
|
|
- $time = date("Y-m-d H:i:s");
|
|
|
- $time1 = date("Y-m-d 00:00:00");
|
|
|
- // 分批同步数据
|
|
|
- Record::where("del_time", 2)
|
|
|
- ->select("id","type","database","order_number","userid")
|
|
|
- ->orderBy("id","desc")
|
|
|
- ->chunkById(10, function ($data) use($connections,$time,$time1){
|
|
|
- $data = $data->toArray();
|
|
|
-
|
|
|
- $name = DDEmployee::whereIn('userid', array_column($data,'userid'))
|
|
|
- ->pluck('name','userid')
|
|
|
- ->toArray();
|
|
|
-
|
|
|
- $id = [];
|
|
|
- foreach ($data as $record) {
|
|
|
- $database = $record['database'];
|
|
|
- $service = $connections[$database] ?? null;
|
|
|
- if (! $service) continue;
|
|
|
- $type = $record['type'];
|
|
|
- $order_number = $record['order_number'];
|
|
|
-
|
|
|
- $system_name = "system";
|
|
|
- if(! empty($name[$record['userid']])) $system_name = $name[$record['userid']];
|
|
|
- if($type == 1){
|
|
|
- $service->db->table("PO_Pomain")
|
|
|
- ->where("cPOID", $order_number)
|
|
|
- ->update([
|
|
|
- "cVerifier" => $system_name,
|
|
|
- "iverifystateex" => 1,
|
|
|
- "cState" => 1,
|
|
|
- "cAuditTime" => $time . ".000",
|
|
|
- "cAuditDate" => $time1 . ".000",
|
|
|
- ]);
|
|
|
- }elseif($type == 2){
|
|
|
- $service->db->table("PU_AppVouch")
|
|
|
- ->where("cCode", $order_number)
|
|
|
- ->update([
|
|
|
- "cVerifier" => $system_name,
|
|
|
- "cAuditTime" => $time . ".000",
|
|
|
- "cAuditDate" => $time1 . ".000",
|
|
|
- ]);
|
|
|
- }else{
|
|
|
- $service->db->table("AP_ApplyPayVouch")
|
|
|
- ->where("cVouchID", $order_number)
|
|
|
- ->update([
|
|
|
- "cCheckMan" => $system_name,
|
|
|
- "dverifysystime" => $time . ".000",
|
|
|
- "dverifydate" => $time1 . ".000",
|
|
|
- ]);
|
|
|
- }
|
|
|
+ public function settle(){
|
|
|
+ $service = new U8ThirtyPartyDatabaseServerService();
|
|
|
+ $minPeriods = $this->getYjData();
|
|
|
+ if(empty($minPeriods['pu_date']) || empty($minPeriods['st_date']) || empty($minPeriods['sa_date'])) {
|
|
|
+ Log::channel('apiLog')->info('月结数据为空', ['msg' => $minPeriods]);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ //单据-----------------
|
|
|
+ $this->orderInsert($service, $minPeriods);
|
|
|
+ }
|
|
|
+
|
|
|
+ public function orderInsert($service, $minPeriods){
|
|
|
+ $pu = $minPeriods['pu_date'] . ' 00:00:00.000';
|
|
|
+ $st = $minPeriods['st_date'] . ' 00:00:00.000';
|
|
|
+ $sa = $minPeriods['sa_date'] . ' 00:00:00.000';
|
|
|
+
|
|
|
+ $dateMap = [
|
|
|
+ SyncTempRecord::type_one => $pu,
|
|
|
+ SyncTempRecord::type_two => $st,
|
|
|
+ SyncTempRecord::type_three => $st,
|
|
|
+ SyncTempRecord::type_four => $sa,
|
|
|
+ SyncTempRecord::type_five => $st,
|
|
|
+ SyncTempRecord::type_six => $sa,
|
|
|
+ SyncTempRecord::type_seven => $st,
|
|
|
+ SyncTempRecord::type_eight => $st,
|
|
|
+ ];
|
|
|
+
|
|
|
+ // 配置不同单据的表名和字段
|
|
|
+ $tasks = [
|
|
|
+ SyncTempRecord::type_one => [// 采购到货 0 |退货 1
|
|
|
+ 'main' => 'PU_ArrivalVouch',
|
|
|
+ 'detail' => 'PU_ArrivalVouchs',
|
|
|
+ 'main_key' => 'ID',
|
|
|
+ 'key' => 'ID',
|
|
|
+ 'whereRaw' => "(dDate >= '{$pu}')",
|
|
|
+ 'main_field' => ['ID as id','cCode as no','dDate as order_date', 'cMakeTime as crt_time', 'cModifyTime as upd_time', 'iBillType as type', 'cverifier as reviewer'],
|
|
|
+ 'son_field' => [
|
|
|
+ 'detail.ID as id',
|
|
|
+// 'detail.ivouchrowno as lineNum',
|
|
|
+// 'detail.cWhCode as warehouseCode',
|
|
|
+ 'detail.cInvCode as materialCode',
|
|
|
+ 'detail.iQuantity as planQty',
|
|
|
+// 'detail.cordercode as from_order',
|
|
|
+ ],
|
|
|
+ 'limit' => 30,
|
|
|
+ ],
|
|
|
+ SyncTempRecord::type_two => [// 领料申请单 材料出库----
|
|
|
+ 'main' => 'MaterialAppVouch',
|
|
|
+ 'detail' => 'MaterialAppVouchs',
|
|
|
+ 'main_key' => 'ID',
|
|
|
+ 'key' => 'ID',
|
|
|
+ 'whereRaw' => "(dDate >= '{$st}')",
|
|
|
+ 'main_field' => ['ID as id','cCode as no', 'dDate as order_date', 'dnmaketime as crt_time', 'dnmodifytime as upd_time','iverifystate as state', 'cHandler as reviewer'],
|
|
|
+ 'son_field' => [
|
|
|
+ 'detail.ID as id',
|
|
|
+// 'detail.ivouchrowno as lineNum',
|
|
|
+// 'detail.cWhCode as warehouseCode',
|
|
|
+ 'detail.cInvCode as materialCode',
|
|
|
+ 'detail.iQuantity as planQty',
|
|
|
+ ],
|
|
|
+ 'limit' => 30,
|
|
|
+ ],
|
|
|
+ SyncTempRecord::type_three => [// 产品报检单 产成品入库流程----- 没有仓库
|
|
|
+ 'main' => 'QMINSPECTVOUCHER',
|
|
|
+ 'detail' => 'QMINSPECTVOUCHERS',
|
|
|
+ 'main_key' => 'ID',
|
|
|
+ 'key' => 'ID',
|
|
|
+ 'whereRaw' => "(DDATE >= '{$st}' and CVOUCHTYPE = 'QM02')",
|
|
|
+ 'main_field' => ['ID as id','CINSPECTCODE as no','DDATE as order_date','DMAKETIME as crt_time', 'DMODIFYTIME as upd_time','CVERIFIER as reviewer'],
|
|
|
+ 'son_field' => [
|
|
|
+ 'detail.ID as id',
|
|
|
+ 'detail.CINVCODE as materialCode',
|
|
|
+ 'detail.FQUANTITY as planQty',
|
|
|
+ 'detail.CDEFINE32 as lottar1',
|
|
|
+ ],
|
|
|
+ 'limit' => 30,
|
|
|
+ ],
|
|
|
+ SyncTempRecord::type_four => [// 销售订单 销售出库流程 ------- 没有仓库
|
|
|
+ 'main' => 'SO_SOMain',
|
|
|
+ 'detail' => 'SO_SODetails',
|
|
|
+ 'main_key' => 'ID',
|
|
|
+ 'key' => 'ID',
|
|
|
+ 'whereRaw' => "(dDate >= '{$sa}')",
|
|
|
+ 'main_field' => ['ID as id','cSOCode as no','dDate as order_date','dcreatesystime as crt_time', 'dmodifysystime as upd_time','cVerifier as reviewer'],
|
|
|
+ 'son_field' => [
|
|
|
+ 'detail.ID as id',
|
|
|
+ 'detail.cInvCode as materialCode',
|
|
|
+ 'detail.iQuantity as planQty',
|
|
|
+ ],
|
|
|
+ 'limit' => 30,
|
|
|
+ ],
|
|
|
+ SyncTempRecord::type_five => [// 其他入 其他入库流程
|
|
|
+ 'main' => 'RdRecord08',
|
|
|
+ 'detail' => 'RdRecords08',
|
|
|
+ 'main_key' => 'ID',
|
|
|
+ 'key' => 'ID',
|
|
|
+ 'whereRaw' => "(dDate >= '{$st}')",
|
|
|
+ 'main_field' => ['ID as id','cCode as no','dDate as order_date','dnmaketime as crt_time', 'dnmodifytime as upd_time','cWhCode as warehouseCode','cHandler as reviewer'],
|
|
|
+ 'son_field' => [
|
|
|
+ 'detail.ID as id',
|
|
|
+ 'detail.cInvCode as materialCode',
|
|
|
+ 'detail.iQuantity as planQty',
|
|
|
+ ],
|
|
|
+ 'limit' => 30,
|
|
|
+ ],
|
|
|
+ SyncTempRecord::type_six => [// 销售退货单 其他入库流程
|
|
|
+ 'main' => 'DispatchList',
|
|
|
+ 'detail' => 'DispatchLists',
|
|
|
+ 'main_key' => 'DLID',
|
|
|
+ 'key' => 'DLID',
|
|
|
+ 'whereRaw' => "(dDate >= '{$st}' and bReturnFlag = 1)",
|
|
|
+ 'main_field' => ['DLID as id','cDLCode as no', 'dDate as order_date','dcreatesystime as crt_time', 'dmodifysystime as upd_time','cVerifier as reviewer'],
|
|
|
+ 'son_field' => [
|
|
|
+ 'detail.DLID as id',
|
|
|
+ 'detail.cInvCode as materialCode',
|
|
|
+ 'detail.cWhCode as warehouseCode',
|
|
|
+ 'detail.iQuantity as planQty',
|
|
|
+ ],
|
|
|
+ 'limit' => 30,
|
|
|
+ ],
|
|
|
+ SyncTempRecord::type_seven => [// 其他出 其他入库流程
|
|
|
+ 'main' => 'RdRecord09',
|
|
|
+ 'detail' => 'RdRecords09',
|
|
|
+ 'main_key' => 'ID',
|
|
|
+ 'key' => 'ID',
|
|
|
+ 'whereRaw' => "(dDate >= '{$st}')",
|
|
|
+ 'main_field' => ['ID as id','cCode as no','dDate as order_date','dnmaketime as crt_time', 'dnmodifytime as upd_time','cWhCode as warehouseCode','cHandler as reviewer'],
|
|
|
+ 'son_field' => [
|
|
|
+ 'detail.ID as id',
|
|
|
+ 'detail.cInvCode as materialCode',
|
|
|
+ 'detail.iQuantity as planQty',
|
|
|
+ ],
|
|
|
+ 'limit' => 30,
|
|
|
+ ],
|
|
|
+ SyncTempRecord::type_eight => [
|
|
|
+ //检验单
|
|
|
+ //cvouchtype=null=>采购到货单 1
|
|
|
+ //cvouchtype=QM04=>产品检验单 2
|
|
|
+ //cvouchtype=QM14=>退货检验单 3
|
|
|
+ 'main' => 'QMCHECKVOUCHER',
|
|
|
+ 'detail' => 'QMCHECKVOUCHERS',
|
|
|
+ 'main_key' => 'ID',
|
|
|
+ 'key' => '',
|
|
|
+ 'whereRaw' => "(DDATE >= '{$st}' and (CVOUCHTYPE = null OR CVOUCHTYPE = 'QM04' OR CVOUCHTYPE = 'QM14'))",
|
|
|
+ 'main_field' => ['ID as id','CCHECKCODE as no','DDATE as order_date','DMAKETIME as crt_time', 'DMODIFYTIME as upd_time','CVERIFIER as reviewer', 'CVOUCHTYPE as type', 'CINVCODE as materialCode', 'CBATCH as lot', 'FREGQUANTITY as hg_quantity', 'FDISQUANTITY as hg_not_quantity', 'FCONQUANTIY as rb_quantity'],
|
|
|
+ 'son_field' => [],
|
|
|
+ 'limit' => 30,
|
|
|
+ ],
|
|
|
+ ];
|
|
|
+
|
|
|
+ $time = time();
|
|
|
+
|
|
|
+ foreach ($tasks as $name => $config) {
|
|
|
+ // 用于记录本次在 U8 查到的所有单号,用来比对删除
|
|
|
+ $currentU8Nos = [];
|
|
|
+ $lastId = 0;
|
|
|
+ $orderDateLimit = $dateMap[$name]; // 当前类型的起始日期限制
|
|
|
+
|
|
|
+ while (true) {
|
|
|
+ list($status, $items) = $service->getPendingBills($config, $lastId);
|
|
|
+ if (!$status || empty($items)) break;
|
|
|
+
|
|
|
+ $nos = collect($items)->pluck('no')->toArray();
|
|
|
+ $currentU8Nos = array_merge($currentU8Nos, $nos); // 记录当前存在的单号
|
|
|
+
|
|
|
+ //获取这 30 条的快照
|
|
|
+ $snapshots = DB::table('sync_snapshot')
|
|
|
+ ->where('type', $name)
|
|
|
+ ->whereIn('u8_no', $nos)
|
|
|
+ ->get()
|
|
|
+ ->keyBy('u8_no');
|
|
|
|
|
|
- $id[] = $record['id'];
|
|
|
+ foreach ($items as $item) {
|
|
|
+ if ($name == SyncTempRecord::type_eight){
|
|
|
+ $type_v = 0;
|
|
|
+ if($item['type'] == null){
|
|
|
+ $type_v = 1;
|
|
|
+ }elseif ($item['type'] == 'QM04'){
|
|
|
+ $type_v = 2;
|
|
|
+ }elseif ($item['type'] == 'QM14'){
|
|
|
+ $type_v = 3;
|
|
|
+ }
|
|
|
+ $item['type'] = $type_v;
|
|
|
}
|
|
|
|
|
|
- // 更新本地数据
|
|
|
- if(! empty($id)) Record::whereIn("id", $id)->update(['del_time' => 3]);
|
|
|
- });
|
|
|
+ $no = $item['no'];
|
|
|
+ $u8Id = $item['id']; // 抓取主表 ID
|
|
|
+ $u8Upd = $item['upd_time'] ?: $item['crt_time'];
|
|
|
+ $snapshot = $snapshots->get($no);
|
|
|
+ $type_2 = isset($item['type']) ? $item['type'] : 0;
|
|
|
+ $bool = $item['reviewer'] ? true : false;
|
|
|
+ if(! $bool) continue;// 没审核跳过
|
|
|
+
|
|
|
+ //退货单没有来源单据的不推送
|
|
|
+// if($name == SyncTempRecord::type_one && $item['type_2'] == 1 && empty($item['details'][0]['from_order'])) continue;
|
|
|
|
|
|
- // ✅ 处理完所有 chunk 后统一关闭连接
|
|
|
- foreach ($connections as $conn) {
|
|
|
- if ($conn instanceof U8DatabaseServerService) {
|
|
|
- $conn->close();
|
|
|
+ $opType = null;
|
|
|
+ if (!$snapshot) {
|
|
|
+ $opType = SyncTempRecord::opt_zero;
|
|
|
+ } elseif ($u8Upd > $snapshot->last_upd_time) {
|
|
|
+ $opType = SyncTempRecord::opt_one;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ($opType !== null) {
|
|
|
+ // 写入任务流水
|
|
|
+ $this->createSyncTask($name, $no, $u8Id, $item, $opType, $u8Upd, $time, $type_2);
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
+ //分页最大id
|
|
|
+ $lastId = collect($items)->max('id');
|
|
|
}
|
|
|
- } catch (\Throwable $e) {
|
|
|
- Log::channel('apiLog')->info('U8数据更新异常', ['msg' => $e->getMessage()]);
|
|
|
+
|
|
|
+ $currentU8NosLookup = array_flip($currentU8Nos);
|
|
|
+
|
|
|
+ // 使用 chunk 配合日期过滤,只查快照中大于等于月结日期的单据
|
|
|
+ DB::table('sync_snapshot')
|
|
|
+ ->where('type', $name)
|
|
|
+ ->where('order_date', '>=', $orderDateLimit) // 关键:缩小快照查询范围
|
|
|
+ ->orderBy('u8_id')
|
|
|
+ ->chunk(100, function ($snapshots) use ($currentU8NosLookup, $name, $time) {
|
|
|
+ foreach ($snapshots as $oldSnapshot) {
|
|
|
+ // 如果快照里的单号不在本次 U8 扫描结果里
|
|
|
+ if (!isset($currentU8NosLookup[$oldSnapshot->u8_no])) {
|
|
|
+ $this->createSyncTask($name, $oldSnapshot->u8_no, $oldSnapshot->u8_id, $oldSnapshot->payload, SyncTempRecord::opt_two, "", $time);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ unset($currentU8Nos); // 释放内存
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ private function createSyncTask($type, $no, $u8Id, $payload, $opType, $u8Upd = "", $time, $type_2 = 0) {
|
|
|
+ $record = SyncTempRecord::create([
|
|
|
+ 'type' => $type,
|
|
|
+ 'type_2' => $type_2,
|
|
|
+ 'u8_no' => $no,
|
|
|
+ 'u8_id' => $u8Id,
|
|
|
+ 'payload' => json_encode($payload),
|
|
|
+ 'u8_upd' => $u8Upd,
|
|
|
+ 'op_type' => $opType,
|
|
|
+ 'crt_time'=> $time,
|
|
|
+ ]);
|
|
|
+
|
|
|
+ // 只分发 ID 给队列,Job 内部再根据此 ID 取 u8_id 和 payload
|
|
|
+ ProcessWMSDataJob::dispatch(['id' => $record->id])->onQueue("sync_wms_order");
|
|
|
+ }
|
|
|
+
|
|
|
+ private function getYjData(){
|
|
|
+ //结账
|
|
|
+ //采购到货单 | 退货单 bflag_PU 采购
|
|
|
+ //领料申请单|产成品入库单| bflag_ST 出和入
|
|
|
+ //销售发货单 销售退货 bflag_SA 销售
|
|
|
+ $result = DB::connection('u8_third_sqlserver')
|
|
|
+ ->table('gl_mend')
|
|
|
+ ->lock('WITH(NOLOCK)')
|
|
|
+ ->selectRaw("
|
|
|
+ MIN(CASE WHEN bflag_PU = 0 AND iyear >= 2023 THEN iYPeriod END) as min_pu,
|
|
|
+ MIN(CASE WHEN bflag_ST = 0 THEN iYPeriod END) as min_st,
|
|
|
+ MIN(CASE WHEN bflag_SA = 0 THEN iYPeriod END) as min_sa
|
|
|
+ ")
|
|
|
+ ->whereRaw("RIGHT(CAST(iYPeriod AS VARCHAR), 2) <> '00'")
|
|
|
+ ->first();
|
|
|
+ // 转换成数组方便取值
|
|
|
+ $minPeriods = (array)$result;
|
|
|
+ $formatDate = function($period) {
|
|
|
+ if (!$period) return null; // 如果没有未结账月份,返回null
|
|
|
+
|
|
|
+ $period = (string)$period; // 确保是字符串
|
|
|
+ $year = substr($period, 0, 4);
|
|
|
+ $month = substr($period, 4, 2);
|
|
|
+
|
|
|
+ return "{$year}-{$month}-01";
|
|
|
+ };
|
|
|
+ // 2. 执行转换
|
|
|
+ $formattedPeriods = [
|
|
|
+ 'pu_date' => $formatDate($minPeriods['min_pu'] ?? null),
|
|
|
+ 'st_date' => $formatDate($minPeriods['min_st'] ?? null),
|
|
|
+ 'sa_date' => $formatDate($minPeriods['min_sa'] ?? null),
|
|
|
+ ];
|
|
|
+
|
|
|
+ return $formattedPeriods;
|
|
|
+ }
|
|
|
}
|