Compare commits
14 Commits
main
...
feature/ju
| Author | SHA1 | Date | |
|---|---|---|---|
| 8fba83d768 | |||
| f06380bcd0 | |||
| 0e0ea619c6 | |||
| 067102ab15 | |||
| a65604ddb9 | |||
| 464f731d9e | |||
| 2a1b663da2 | |||
| b9bbba31b7 | |||
| 440f06079f | |||
| b9e0835ef5 | |||
| 3766fe4d4b | |||
| 8cae97df0d | |||
| f580807097 | |||
| 9190ecff67 |
@ -27,7 +27,7 @@ class JstDump extends Command
|
||||
['actual_weight', '实称重量'], ['online_weight', '线上重量'], ['freight', '运费'],
|
||||
['ship_time', '发货时间'], ['pay_time', '付款时间'], ['product_code', '货号'],
|
||||
['receiver_state', '省'], ['receiver_city', '市'], ['receiver_district', '区'],
|
||||
['package_no', '配货单号'], ['amount', '金额'],
|
||||
['package_no', '配货单号'], ['amount', '金额'], ['express_name1', '快递名称'],
|
||||
];
|
||||
$fh = fopen('php://output', 'w');
|
||||
fwrite($fh, chr(0xEF).chr(0xBB).chr(0xBF));
|
||||
|
||||
@ -38,6 +38,21 @@ return [
|
||||
'retry_sleep_ms' => (int) env('JST_RETRY_SLEEP_MS', 1000),
|
||||
],
|
||||
|
||||
// 发货数据「导出明细」体积口径(对齐工作平台 OmsDataDay:明细体积默认 = 数量 × 长×宽×高)。
|
||||
// 依据:工作平台 9.1-9.16 导出明细,非代发仓 8421/8421 行乘数量;代发仓走简尚线路快递的不乘数量。
|
||||
// 合并口径体积不受此影响(单独存 m_volume_cm3)。
|
||||
'detail_volume' => [
|
||||
// 这些发货仓的明细体积不乘数量(工厂代发虚拟仓)
|
||||
'no_qty_warehouses' => ['常州简尚家居有限公司'],
|
||||
// 上述仓库中,用这些标准承运商发货时仍乘数量
|
||||
'qty_carriers_in_no_qty_warehouses' => [
|
||||
'中通快运', '韵达快递', '申通E物流', '安能物流', '邮政电商标快', '邮政快递包裹POSTB',
|
||||
'壹米滴答', '百世物流', '德邦快递', '中通速递', '圆通速递',
|
||||
],
|
||||
// 这些快递的明细体积一律为 0
|
||||
'zero_volume_expresses' => ['白云韵达-天猫亿家达', '中通礼品单'],
|
||||
],
|
||||
|
||||
// 接口方法名(对应工作平台 ErpTradeData 中的调用)。
|
||||
'methods' => [
|
||||
'sctrade_list' => 'erp.sctrade.query', // 出库单列表(按时间窗分页)
|
||||
|
||||
@ -65,6 +65,13 @@ class SyncJushuitanShipping extends Command
|
||||
$packageSummary = isset($result['unique_packages'])
|
||||
? sprintf('唯一包裹源键 %d 个,包裹记录处理 %d 次;', $result['unique_packages'], $result['packages'] ?? 0)
|
||||
: '';
|
||||
if (isset($result['outbound']) || isset($result['purchase_out'])) {
|
||||
$this->info(sprintf(
|
||||
' 出库单兜底补出 %d 条明细,采购退货出库 %d 条明细(对齐工作平台发货数据口径)。',
|
||||
(int) ($result['outbound'] ?? 0),
|
||||
(int) ($result['purchase_out'] ?? 0),
|
||||
));
|
||||
}
|
||||
if ($result['freight_incomplete'] ?? false) {
|
||||
$this->warn('本次窗口' . $packageSummary . $summary . ';新记录运费与结算重量待补齐,空白不代表 0。');
|
||||
} else {
|
||||
|
||||
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* 组合件(视图一行多条码)拆件后:明细行存部件自己的名称/尺寸/体积,
|
||||
* 合并导出改用以下"合并用"列(整行值),对齐工作平台两种口径。普通行这些列为空。
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
private array $cols = ['m_name', 'm_volume_cm3', 'm_length_cm', 'm_width_cm', 'm_height_cm'];
|
||||
|
||||
private function conn(): \Illuminate\Database\Schema\Builder
|
||||
{
|
||||
return Schema::connection((string) config('jushuitan.connection', 'jushuitan_local'));
|
||||
}
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
$schema = $this->conn();
|
||||
if (! $schema->hasTable('jst_oms_shipping')) {
|
||||
return;
|
||||
}
|
||||
$schema->table('jst_oms_shipping', function (Blueprint $table) use ($schema): void {
|
||||
if (! $schema->hasColumn('jst_oms_shipping', 'm_name')) {
|
||||
$table->string('m_name', 500)->nullable()->comment('合并用商品名称(组合件整行)');
|
||||
}
|
||||
if (! $schema->hasColumn('jst_oms_shipping', 'm_volume_cm3')) {
|
||||
$table->decimal('m_volume_cm3', 18, 4)->nullable()->comment('合并用体积(组合件整行均摊)');
|
||||
}
|
||||
foreach (['m_length_cm' => '长', 'm_width_cm' => '宽', 'm_height_cm' => '高'] as $c => $label) {
|
||||
if (! $schema->hasColumn('jst_oms_shipping', $c)) {
|
||||
$table->decimal($c, 12, 2)->nullable()->comment('合并用' . $label . '(组合件整行)');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$schema = $this->conn();
|
||||
if (! $schema->hasTable('jst_oms_shipping')) {
|
||||
return;
|
||||
}
|
||||
$drop = array_values(array_filter($this->cols, fn ($c) => $schema->hasColumn('jst_oms_shipping', $c)));
|
||||
if ($drop) {
|
||||
$schema->table('jst_oms_shipping', function (Blueprint $table) use ($drop): void {
|
||||
$table->dropColumn($drop);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -17,6 +17,11 @@ class ShippingOrderRepository
|
||||
public function __construct()
|
||||
{
|
||||
$this->db = DB::connection((string) config('jushuitan.connection', 'jushuitan_local'));
|
||||
try {
|
||||
// 合并取"最后一行"值用 GROUP_CONCAT,放宽默认 1024 长度避免截断
|
||||
$this->db->statement('SET SESSION group_concat_max_len = 4194304');
|
||||
} catch (\Throwable) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -36,7 +41,7 @@ class ShippingOrderRepository
|
||||
->orderByDesc('source_id')
|
||||
->orderBy('sku_source_id')
|
||||
->forPage($page, $perPage)
|
||||
->get()->map(fn ($r) => (array) $r)->all();
|
||||
->get()->map(fn ($r) => $this->detailRow((array) $r))->all();
|
||||
|
||||
return ['data' => $rows, 'total' => $total];
|
||||
}
|
||||
@ -55,6 +60,28 @@ class ShippingOrderRepository
|
||||
return ['data' => $rows, 'total' => $total];
|
||||
}
|
||||
|
||||
/** 明细口径:无尺寸(0)的长宽高/体积显示为空白,对齐工作平台导出明细(合并保持 0)。 */
|
||||
private function detailRow(array $r): array
|
||||
{
|
||||
foreach (['length_cm', 'width_cm', 'height_cm', 'volume_cm3'] as $c) {
|
||||
if (array_key_exists($c, $r) && $r[$c] !== null && $r[$c] !== '' && (float) $r[$c] == 0.0) {
|
||||
$r[$c] = null;
|
||||
}
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
/**
|
||||
* 包裹内"最后一行"(按明细 id 顺序)的值。工作平台合并的商品名称/供应商取的是
|
||||
* 条码串最后一个商品那行(样本 6213/6216、575/575),不是 MIN。
|
||||
*/
|
||||
private function lastOf(string $expr): string
|
||||
{
|
||||
// SEPARATOR 只能是字符串常量;用名称里不会出现的 '#~#' 作分隔
|
||||
return "NULLIF(SUBSTRING_INDEX(GROUP_CONCAT(COALESCE({$expr}, '') ORDER BY `id` SEPARATOR '#~#'), '#~#', -1), '')";
|
||||
}
|
||||
|
||||
/** 合并聚合 SELECT:条码/商品ID 逗号拼接、数量/重量/体积/金额/运费求和、长宽高取最大、其余取值。 */
|
||||
private function mergedSelectRaw(): string
|
||||
{
|
||||
@ -71,14 +98,22 @@ class ShippingOrderRepository
|
||||
'weight_kg', 'settle_weight_kg', 'settle_volume_cm3', 'recon_weight_kg', 'recon_volume_cm3',
|
||||
'finished_barcode', 'finished_name', 'finished_supplier', 'settle_freight', 'front_no'];
|
||||
|
||||
// 组合件拆件后明细存部件值,合并取整行值(m_*),普通行 m_* 为空则回落原列
|
||||
$mcol = ['product_name' => 'm_name', 'volume_cm3' => 'm_volume_cm3',
|
||||
'length_cm' => 'm_length_cm', 'width_cm' => 'm_width_cm', 'height_cm' => 'm_height_cm'];
|
||||
$parts = ['MAX(id) as id', 'source_id'];
|
||||
foreach ($all as $c) {
|
||||
if (in_array($c, $sum, true)) {
|
||||
if ($c === 'product_name') {
|
||||
$parts[] = $this->lastOf("COALESCE(`m_name`, `product_name`)") . " as `{$c}`";
|
||||
} elseif (isset($mcol[$c])) {
|
||||
$fn = $c === 'volume_cm3' ? 'SUM' : 'MAX';
|
||||
$parts[] = "{$fn}(COALESCE(`{$mcol[$c]}`, `{$c}`)) as `{$c}`";
|
||||
} elseif (in_array($c, $sum, true)) {
|
||||
$parts[] = "SUM(`{$c}`) as `{$c}`";
|
||||
} elseif (in_array($c, $concat, true)) {
|
||||
$parts[] = "GROUP_CONCAT(DISTINCT `{$c}` SEPARATOR ',') as `{$c}`";
|
||||
} elseif (in_array($c, $min, true)) {
|
||||
$parts[] = "MIN(`{$c}`) as `{$c}`";
|
||||
$parts[] = $this->lastOf("`{$c}`") . " as `{$c}`";
|
||||
} else {
|
||||
$parts[] = "MAX(`{$c}`) as `{$c}`";
|
||||
}
|
||||
@ -107,7 +142,7 @@ class ShippingOrderRepository
|
||||
return;
|
||||
}
|
||||
foreach ($rows as $row) {
|
||||
yield (array) $row;
|
||||
yield $this->detailRow((array) $row);
|
||||
}
|
||||
$last = (int) $rows[array_key_last($rows)]->id;
|
||||
if (count($rows) < $batchSize) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user