feat(快递入驻/快递资料): 生成二维码时必填快递资料并对齐到快递资料;去掉「发起报价变更」按钮;自定义3 改名扣款方式
- 生成入驻二维码新增 11 个必填项(快递方看不到,放在入驻流程下方单独一块):快递类型、快递合作方式、快递属性、扣款方式、单号类型、快递邮箱、 是否需要核对物流点、快递发货方式、是否已有工作平台账号、快递网点代码、网点所在地区;入驻列表、入驻详情可查看和修改 - 快递资料:扣款方式对齐到「扣款方式」列(工作平台没填时用入驻的),其余字段接在入驻信息列里;网点代码/地区进网点明细;导出同步 - 不再依赖钉钉「新建快递」流程字段,ERP 开通改为手动补录 ERP账户ID - 快递资料「自定义3」列、筛选、编辑和导出表头改名为「扣款方式」(字段仍是 undefined3) - 报价管理工具栏、报价历史页去掉「发起报价变更」:它默认拿第一份报价走老的改格子流程,对入驻快递会绕开后台变价; 变价统一从报价列表每一行的「变价」进入;老报价编辑页新增 …/changes/new 入口,避免套餐限制中间件把 GET …/create 跳到用户页 - 新增迁移 2026_10_14_300000:business_courier_onboardings 加 11 个可空字段 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019gzfsnV3fJ89CoUy1D9V9g
This commit is contained in:
parent
c0aab60862
commit
8ba7ac8327
@ -64,6 +64,7 @@ final class CourierProfileData
|
||||
'linker' => $onboarding->contact_name,
|
||||
'linkmobile' => $onboarding->contact_phone,
|
||||
'dzqzjbr' => $onboarding->esign_account,
|
||||
'undefined3' => $onboarding->deduction_method,
|
||||
'modified' => $onboarding->updated_at?->toDateTimeString(),
|
||||
'_onboarding_only' => true,
|
||||
'_info' => $info,
|
||||
@ -145,6 +146,44 @@ final class CourierProfileData
|
||||
];
|
||||
}
|
||||
|
||||
/** 快递资料右侧接的入驻字段(我方填写;扣款方式对齐到左边「扣款方式」列,不重复显示)。 */
|
||||
public const APPENDED_PROFILE_FIELDS = [
|
||||
'courier_category', 'cooperation_mode', 'courier_attribute', 'waybill_type', 'shipping_mode',
|
||||
'need_logistics_check', 'workplatform_account', 'courier_email', 'network_code', 'network_region',
|
||||
];
|
||||
|
||||
/** 工作平台的行:扣款方式没填时用入驻里我方填的。 */
|
||||
public function fillFromOnboarding(object $row): object
|
||||
{
|
||||
$onboarding = $row->_info['onboarding'] ?? null;
|
||||
if ($onboarding !== null && blank($row->undefined3 ?? null) && filled($onboarding->deduction_method)) {
|
||||
$row = clone $row;
|
||||
$row->undefined3 = $onboarding->deduction_method;
|
||||
}
|
||||
|
||||
return $row;
|
||||
}
|
||||
|
||||
/** 入驻里填的网点,按工作平台网点表的列铺成一行(排在网点明细最前面)。 */
|
||||
public function onboardingNetwork(CourierOnboarding $onboarding): ?object
|
||||
{
|
||||
if (blank($onboarding->network_code) && blank($onboarding->network_name) && blank($onboarding->network_region)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (object) [
|
||||
'id' => '入驻 ' . $onboarding->number,
|
||||
'expcode' => $onboarding->workplatform_expcode,
|
||||
'netcode' => $onboarding->network_code,
|
||||
'netname' => $onboarding->network_name,
|
||||
'address' => $onboarding->network_region,
|
||||
'linker' => $onboarding->contact_name,
|
||||
'linkermobile' => $onboarding->contact_phone,
|
||||
'status' => $onboarding->status === CourierOnboarding::STATUS_ACTIVATED ? '1' : '0',
|
||||
'created' => $onboarding->created_at?->toDateTimeString(),
|
||||
];
|
||||
}
|
||||
|
||||
/** 保存编辑:只记和当前显示值不同的字段,并写一条操作日志。 */
|
||||
public function update(string $expcode, ?string $courierName, object $current, array $values, int $userId): int
|
||||
{
|
||||
|
||||
@ -31,11 +31,13 @@ class CourierOnboardings extends Controller
|
||||
'invite_label' => ['nullable', 'string', 'max:100'],
|
||||
'valid_days' => ['nullable', 'integer', 'min:1', 'max:180'],
|
||||
'workplatform_expcode' => ['required', 'string', 'max:64', 'regex:/^[0-9A-Za-z_\-]+$/'],
|
||||
...CourierOnboarding::profileRules(),
|
||||
], [
|
||||
'courier_name.required' => '请先定好系统快递名称(需与报价名、发货数据里的快递名称一致)。',
|
||||
'workplatform_expcode.required' => '请填写快递公司代码(与快递资料「快递公司代码」一致)。',
|
||||
'workplatform_expcode.regex' => '快递公司代码只能包含字母、数字、下划线和短横线。',
|
||||
]);
|
||||
...CourierOnboarding::profileMessages(),
|
||||
], CourierOnboarding::profileAttributes());
|
||||
$code = strtoupper(trim((string) $data['workplatform_expcode']));
|
||||
$taken = CourierOnboarding::query()
|
||||
->where('workplatform_expcode', $code)
|
||||
@ -51,7 +53,7 @@ class CourierOnboardings extends Controller
|
||||
(int) user_id(),
|
||||
$data['courier_name'],
|
||||
);
|
||||
$onboarding->update(['workplatform_expcode' => $code]);
|
||||
$onboarding->update(['workplatform_expcode' => $code, ...$this->profileValues($data)]);
|
||||
|
||||
return redirect()->route('business.courier-onboardings.show', $onboarding)
|
||||
->with('success', '入驻二维码已生成,发给快递方扫码填写即可。');
|
||||
@ -141,6 +143,17 @@ class CourierOnboardings extends Controller
|
||||
->with('success', "变价单 {$change->number} 已提交审核。审核通过后会自动推送到快递的 e签宝签署。");
|
||||
}
|
||||
|
||||
/** @return array<string,?string> */
|
||||
private function profileValues(array $data): array
|
||||
{
|
||||
$values = [];
|
||||
foreach (array_keys(CourierOnboarding::PROFILE_FIELDS) as $field) {
|
||||
$values[$field] = filled($data[$field] ?? null) ? trim((string) $data[$field]) : null;
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
private function requotes(): \App\Support\CourierRequoteService
|
||||
{
|
||||
return app(\App\Support\CourierRequoteService::class);
|
||||
@ -212,8 +225,19 @@ class CourierOnboardings extends Controller
|
||||
$data = $request->validate([
|
||||
'courier_name' => ['nullable', 'string', 'max:100'],
|
||||
'reconciler' => ['nullable', 'string', 'max:100'],
|
||||
]);
|
||||
$this->service->updateInternal($onboarding, $data, (int) user_id());
|
||||
...CourierOnboarding::profileRules(true),
|
||||
], CourierOnboarding::profileMessages(), CourierOnboarding::profileAttributes());
|
||||
if ($request->hasAny(['courier_name', 'reconciler'])) {
|
||||
// 只提交了其中一项时,另一项沿用原值。
|
||||
$data['courier_name'] = $request->has('courier_name') ? ($data['courier_name'] ?? null) : $onboarding->courier_name;
|
||||
$data['reconciler'] = $request->has('reconciler') ? ($data['reconciler'] ?? null) : $onboarding->reconciler;
|
||||
$this->service->updateInternal($onboarding, $data, (int) user_id());
|
||||
}
|
||||
// 表单里带了快递资料字段才更新(只改名称/对账人的旧表单不会清空它们)。
|
||||
$profile = array_intersect_key($this->profileValues($data), $request->only(array_keys(CourierOnboarding::PROFILE_FIELDS)));
|
||||
if ($profile !== []) {
|
||||
$onboarding->update([...$profile, 'updated_by' => (int) user_id()]);
|
||||
}
|
||||
|
||||
return $this->back($onboarding, '内部信息已保存。');
|
||||
}
|
||||
|
||||
@ -6526,9 +6526,11 @@ class Pages extends Controller
|
||||
fputcsv($csv, [
|
||||
'ID', '快递公司代码', '快递公司名称', '外部编码', '杉橙快递代码', '运费打款方式',
|
||||
'是否启用', '可达服务', '是否快运', '自动寻号', '配货单号寻号', '数量拆单', '重量0寻号',
|
||||
'停运时间', '合同开始时间', '合同结束时间', '联系人', '联系电话', '自定义1', '自定义2', '自定义3',
|
||||
'停运时间', '合同开始时间', '合同结束时间', '联系人', '联系电话', '自定义1', '自定义2', '扣款方式',
|
||||
'体积0寻号', '手工单号', '解密', '电子签章经办人', '最后修改',
|
||||
'入驻单号', '入驻状态', '入驻主体', '财务系统已修改字段',
|
||||
'入驻单号', '入驻状态', '入驻主体',
|
||||
...array_map(static fn (string $field): string => \App\Models\Business\CourierOnboarding::PROFILE_FIELDS[$field][0], \App\Business\CourierProfileData::APPENDED_PROFILE_FIELDS),
|
||||
'财务系统已修改字段',
|
||||
]);
|
||||
|
||||
$bool = static fn (mixed $value): string => in_array(strtolower((string) $value), ['1', 'true', 'yes', 'y'], true) || $value === true ? '是' : '否';
|
||||
@ -6546,8 +6548,9 @@ class Pages extends Controller
|
||||
$overrides ??= \Illuminate\Support\Facades\Schema::hasTable('business_courier_profiles')
|
||||
? \App\Models\Business\CourierProfile::query()->get()->mapWithKeys(static fn ($profile): array => [(string) $profile->expcode => (array) $profile->overrides])->all()
|
||||
: [];
|
||||
$row = $profiles->apply($row, $overrides[(string) ($row->expcode ?? '')] ?? []);
|
||||
$info = $row->_info ?? $overview->infoFor((string) ($row->expcode ?? ''), $row->expname ?? null);
|
||||
$row->_info = $info;
|
||||
$row = $profiles->apply($profiles->fillFromOnboarding($row), $overrides[(string) ($row->expcode ?? '')] ?? []);
|
||||
$onboarding = $info['onboarding'] ?? null;
|
||||
fputcsv($csv, [
|
||||
$row->Id ?? '',
|
||||
@ -6579,6 +6582,7 @@ class Pages extends Controller
|
||||
$this->csvText($onboarding?->number),
|
||||
$this->csvText($onboarding?->statusLabel()),
|
||||
$this->csvText($onboarding ? $onboarding->entityLabel() . ' · ' . $onboarding->company_full_name : null),
|
||||
...array_map(fn (string $field): string => $this->csvText($onboarding?->{$field}), \App\Business\CourierProfileData::APPENDED_PROFILE_FIELDS),
|
||||
$this->csvText(implode('、', array_map(static fn (string $field): string => \App\Models\Business\CourierProfile::EDITABLE[$field], $row->_overridden ?? []))),
|
||||
]);
|
||||
}
|
||||
@ -6841,6 +6845,7 @@ class Pages extends Controller
|
||||
|
||||
return $row;
|
||||
}, $rows->items());
|
||||
$platformRows = array_map([$profiles, 'fillFromOnboarding'], $platformRows);
|
||||
$displayRows = array_merge(array_map([$profiles, 'onboardingRow'], $append['extra']), $platformRows);
|
||||
$overrides = $profiles->overrides(array_map(static fn (object $row): string => (string) ($row->expcode ?? ''), $displayRows));
|
||||
$displayRows = array_map(static fn (object $row): object => $profiles->apply($row, $overrides[(string) ($row->expcode ?? '')] ?? []), $displayRows);
|
||||
@ -6905,6 +6910,10 @@ class Pages extends Controller
|
||||
report($exception);
|
||||
}
|
||||
|
||||
if ($onboarding !== null && ($network = $profiles->onboardingNetwork($onboarding)) !== null) {
|
||||
array_unshift($networks, $network);
|
||||
}
|
||||
|
||||
return [
|
||||
'code' => $code,
|
||||
'row' => $row,
|
||||
|
||||
@ -31,6 +31,61 @@ class CourierOnboarding extends Model
|
||||
self::STATUS_CANCELLED => '已作废',
|
||||
];
|
||||
|
||||
/**
|
||||
* 生成二维码时我方必填的快递资料(快递方看不到),直接对齐到快递资料。
|
||||
* 字段 => [名称, 可选值(null 为自由填写)]
|
||||
*/
|
||||
public const PROFILE_FIELDS = [
|
||||
'courier_category' => ['快递类型', ['内采快递', '外采快递']],
|
||||
'cooperation_mode' => ['快递合作方式', ['保丢保损', '保丢不保损', '不保丢不保损']],
|
||||
'courier_attribute' => ['快递属性', ['简尚', '工厂']],
|
||||
'deduction_method' => ['扣款方式', ['运费', '损耗+运费', '无']],
|
||||
'waybill_type' => ['单号类型', ['系统对接', '手填单号']],
|
||||
'courier_email' => ['快递邮箱', null],
|
||||
'need_logistics_check' => ['是否需要核对物流点', ['是', '否']],
|
||||
'shipping_mode' => ['快递发货方式', ['一单一货', '一单多货']],
|
||||
'workplatform_account' => ['是否已有工作平台账号', ['已有', '新开']],
|
||||
'network_code' => ['快递网点代码', null],
|
||||
'network_region' => ['网点所在地区', null],
|
||||
];
|
||||
|
||||
/**
|
||||
* 校验规则:生成二维码时全部必填;入驻详情里修改时,提交了哪项就校验哪项(不能清空)。
|
||||
*
|
||||
* @return array<string,list<string>>
|
||||
*/
|
||||
public static function profileRules(bool $onlyPresent = false): array
|
||||
{
|
||||
$rules = [];
|
||||
foreach (self::PROFILE_FIELDS as $field => [$label, $options]) {
|
||||
$base = $onlyPresent ? ['sometimes', 'required'] : ['required'];
|
||||
$rules[$field] = [...$base, ...match (true) {
|
||||
$options !== null => ['in:' . implode(',', $options)],
|
||||
$field === 'courier_email' => ['email', 'max:191'],
|
||||
default => ['string', 'max:' . ($field === 'network_code' ? 64 : 191)],
|
||||
}];
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
/** @return array<string,string> 必填提示 */
|
||||
public static function profileMessages(): array
|
||||
{
|
||||
$messages = [];
|
||||
foreach (self::PROFILE_FIELDS as $field => [$label, $options]) {
|
||||
$messages[$field . '.required'] = ($options !== null ? '请选择' : '请填写') . $label . '。';
|
||||
}
|
||||
|
||||
return $messages;
|
||||
}
|
||||
|
||||
/** @return array<string,string> 字段名称,用于校验提示 */
|
||||
public static function profileAttributes(): array
|
||||
{
|
||||
return array_map(static fn (array $config): string => $config[0], self::PROFILE_FIELDS);
|
||||
}
|
||||
|
||||
/** 快递方可以继续编辑资料的状态。 */
|
||||
public const COURIER_EDITABLE = [self::STATUS_INVITED, self::STATUS_RETURNED];
|
||||
|
||||
@ -63,6 +118,8 @@ class CourierOnboarding extends Model
|
||||
'bank_account_name', 'bank_name', 'bank_account_number', 'invoice_type', 'tax_rate', 'settlement_cycle',
|
||||
'private_account_name', 'private_bank_name', 'private_account_number',
|
||||
'workplatform_expcode', 'erp_account_id', 'erp_opened_at', 'erp_opened_source', 'dingtalk_instance_id',
|
||||
'courier_category', 'cooperation_mode', 'courier_attribute', 'deduction_method', 'waybill_type', 'courier_email',
|
||||
'need_logistics_check', 'shipping_mode', 'workplatform_account', 'network_code', 'network_region',
|
||||
'quote_mode', 'volumetric_rule', 'volumetric_divisor', 'quote_effective_date', 'quote_structure', 'quote_rows',
|
||||
'min_weight', 'weight_rounding', 'per_ticket_surcharge', 'quote_note', 'remark',
|
||||
'courier_name', 'reconciler', 'return_reason', 'submitted_at',
|
||||
|
||||
@ -23,7 +23,7 @@ class CourierProfile extends Model
|
||||
'linkmobile' => '联系电话',
|
||||
'undefined1' => '自定义1',
|
||||
'undefined2' => '自定义2',
|
||||
'undefined3' => '自定义3',
|
||||
'undefined3' => '扣款方式',
|
||||
'dzqzjbr' => '电子签章经办人',
|
||||
];
|
||||
|
||||
|
||||
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
/**
|
||||
* 生成入驻二维码时我方选填的快递资料(快递类型、合作方式、扣款方式、网点代码等),
|
||||
* 直接对齐到快递资料,不再依赖钉钉「新建快递」流程字段。
|
||||
*/
|
||||
return new class extends Migration
|
||||
{
|
||||
private const COLUMNS = [
|
||||
'courier_category' => 32, 'cooperation_mode' => 32, 'courier_attribute' => 32, 'deduction_method' => 32,
|
||||
'waybill_type' => 32, 'courier_email' => 191, 'need_logistics_check' => 8, 'shipping_mode' => 32,
|
||||
'workplatform_account' => 16, 'network_code' => 64, 'network_region' => 191,
|
||||
];
|
||||
|
||||
public function up(): void
|
||||
{
|
||||
if (! Schema::hasTable('business_courier_onboardings')) {
|
||||
return;
|
||||
}
|
||||
Schema::table('business_courier_onboardings', function (Blueprint $table): void {
|
||||
foreach (self::COLUMNS as $column => $length) {
|
||||
if (! Schema::hasColumn('business_courier_onboardings', $column)) {
|
||||
$table->string($column, $length)->nullable();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
if (! Schema::hasTable('business_courier_onboardings')) {
|
||||
return;
|
||||
}
|
||||
Schema::table('business_courier_onboardings', function (Blueprint $table): void {
|
||||
foreach (array_keys(self::COLUMNS) as $column) {
|
||||
if (Schema::hasColumn('business_courier_onboardings', $column)) {
|
||||
$table->dropColumn($column);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -408,7 +408,7 @@
|
||||
<input id="courier-custom-2" name="undefined2" type="text" value="{{ $filters['undefined2'] ?? '' }}">
|
||||
</div>
|
||||
<div class="courier-information-field">
|
||||
<label for="courier-custom-3">自定义3</label>
|
||||
<label for="courier-custom-3">扣款方式</label>
|
||||
<input id="courier-custom-3" name="undefined3" type="text" value="{{ $filters['undefined3'] ?? '' }}">
|
||||
</div>
|
||||
<div class="courier-information-field">
|
||||
@ -464,9 +464,9 @@
|
||||
<tr>
|
||||
<th>ID</th><th>快递公司代码</th><th>快递公司名称</th><th>外部编码</th><th>杉橙快递代码</th><th>运费打款方式</th>
|
||||
<th>是否启用</th><th>可达服务</th><th>是否快运</th><th>自动寻号</th><th>配货单号寻号</th><th>数量拆单</th><th>重量0寻号</th>
|
||||
<th>停运时间</th><th>合同开始时间</th><th>合同结束时间</th><th>联系人</th><th>联系电话</th><th>自定义1</th><th>自定义2</th><th>自定义3</th>
|
||||
<th>停运时间</th><th>合同开始时间</th><th>合同结束时间</th><th>联系人</th><th>联系电话</th><th>自定义1</th><th>自定义2</th><th>扣款方式</th>
|
||||
<th>体积0寻号</th><th>手工单号</th><th>解密</th><th>电子签章经办人</th><th>最后修改</th>
|
||||
<th class="is-onboarding">入驻单号</th><th class="is-onboarding">入驻状态</th><th class="is-onboarding">ERP 开通</th><th class="is-onboarding">入驻主体</th>
|
||||
<th class="is-onboarding">入驻单号</th><th class="is-onboarding">入驻状态</th><th class="is-onboarding">ERP 开通</th><th class="is-onboarding">入驻主体</th>@foreach (\App\Business\CourierProfileData::APPENDED_PROFILE_FIELDS as $profileField)<th class="is-onboarding">{{ \App\Models\Business\CourierOnboarding::PROFILE_FIELDS[$profileField][0] }}</th>@endforeach
|
||||
<th class="is-onboarding">证照</th><th class="is-onboarding">生效报价</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@ -516,7 +516,7 @@
|
||||
@include('business.pages.courier-payables.partials.courier-onboarding-cells', ['info' => $row->_info ?? null, 'platformName' => $row->expname ?? null, 'platformCode' => $row->expcode ?? null])
|
||||
</tr>
|
||||
@empty
|
||||
<tr><td colspan="32" class="courier-information-empty">{{ $courierError ? '数据暂时不可用。' : '当前筛选条件下没有快递资料。' }}</td></tr>
|
||||
<tr><td colspan="42" class="courier-information-empty">{{ $courierError ? '数据暂时不可用。' : '当前筛选条件下没有快递资料。' }}</td></tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@ -53,7 +53,7 @@
|
||||
.cod__stack { display:grid; gap:10px; }
|
||||
.cod__row { display:flex; flex-wrap:wrap; gap:8px; }
|
||||
.cod__field { display:grid; gap:5px; } .cod__field label { color:var(--muted); font-size:11px; font-weight:600; }
|
||||
.cod__field input, .cod__field textarea { width:100%; min-height:34px; padding:6px 10px; border:1px solid var(--line); border-radius:8px; background:#fff; color:var(--ink); font:inherit; }
|
||||
.cod__field input, .cod__field textarea, .cod__field select { width:100%; min-height:34px; padding:6px 10px; border:1px solid var(--line); border-radius:8px; background:#fff; color:var(--ink); font:inherit; }
|
||||
.cod__field textarea { min-height:64px; resize:vertical; }
|
||||
.cod__field input:focus, .cod__field textarea:focus { border-color:var(--gold); outline:none; box-shadow:0 0 0 3px rgba(133,102,50,.18); }
|
||||
.cod__help { color:var(--muted); font-size:11px; line-height:1.55; }
|
||||
@ -394,6 +394,32 @@
|
||||
@endif
|
||||
</div>
|
||||
</section>
|
||||
<section class="cod__panel" aria-labelledby="cod-profile">
|
||||
<div class="cod__panel-head"><h2 class="cod__panel-title" id="cod-profile"><span class="material-icons-outlined" aria-hidden="true">local_shipping</span>快递资料(我方填写)</h2></div>
|
||||
<div class="cod__panel-body">
|
||||
<form method="POST" action="{{ route('business.courier-onboardings.internal', $onboarding) }}" class="cod__stack">
|
||||
@csrf
|
||||
<p class="cod__help" style="margin:0">快递方看不到。保存后对齐到快递资料(扣款方式、网点代码等),代码 {{ $onboarding->workplatform_expcode ?: '未填' }}。</p>
|
||||
@foreach (\App\Models\Business\CourierOnboarding::PROFILE_FIELDS as $field => [$label, $options])
|
||||
<div class="cod__field">
|
||||
<label for="cod-profile-{{ $field }}">{{ $label }} *</label>
|
||||
@if ($options !== null)
|
||||
<select id="cod-profile-{{ $field }}" name="{{ $field }}" required>
|
||||
<option value=""></option>
|
||||
@foreach ($options as $option)
|
||||
<option value="{{ $option }}" @selected(old($field, $onboarding->{$field}) === $option)>{{ $option }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@else
|
||||
<input id="cod-profile-{{ $field }}" name="{{ $field }}" required type="{{ $field === 'courier_email' ? 'email' : 'text' }}" maxlength="{{ $field === 'network_code' ? 64 : 191 }}" value="{{ old($field, $onboarding->{$field}) }}">
|
||||
@endif
|
||||
@error($field)<span class="cod__help" style="color:#b80000">{{ $message }}</span>@enderror
|
||||
</div>
|
||||
@endforeach
|
||||
<button type="submit" class="cod__button">保存快递资料</button>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
@if ($status === 'activated')
|
||||
<section class="cod__panel" aria-labelledby="cod-erp">
|
||||
<div class="cod__panel-head"><h2 class="cod__panel-title" id="cod-erp"><span class="material-icons-outlined" aria-hidden="true">hub</span>ERP 开通</h2>
|
||||
@ -401,7 +427,7 @@
|
||||
</div>
|
||||
<div class="cod__panel-body cod__stack">
|
||||
@if ($onboarding->erpPending())
|
||||
<p class="cod__help" style="margin:0">下一步:ERP 专员在钉钉发起「新建快递」流程,开通发货系统账号。流程完结后,流程里填的快递代码、ERP账户ID 会自动补到这里和快递资料。</p>
|
||||
<p class="cod__help" style="margin:0">下一步:ERP 专员开通发货系统账号后,在下方「手动补录」里填 ERP账户ID 保存即可(快递公司代码沿用生成二维码时填的)。快递类型、扣款方式等在上方「快递资料(我方填写)」维护,直接对齐到快递资料。</p>
|
||||
@else
|
||||
<dl class="cod__meta" style="grid-template-columns:1fr 1fr">
|
||||
<div><dt>快递代码</dt><dd>{{ $onboarding->workplatform_expcode }}</dd></div>
|
||||
@ -411,7 +437,7 @@
|
||||
</dl>
|
||||
@endif
|
||||
<details>
|
||||
<summary class="cod__help" style="cursor:pointer">钉钉流程同步不到时手动补录</summary>
|
||||
<summary class="cod__help" style="cursor:pointer">手动补录 ERP 开通信息</summary>
|
||||
<form method="POST" action="{{ route('business.courier-onboardings.erp-opening', $onboarding) }}" class="cod__stack" style="margin-top:10px">
|
||||
@csrf
|
||||
<div class="cod__field"><label for="cod-erp-code">快递代码</label><input id="cod-erp-code" name="workplatform_expcode" type="text" maxlength="64" value="{{ $onboarding->workplatform_expcode }}" placeholder="ERP 开通后的快递代码"></div>
|
||||
|
||||
@ -27,13 +27,13 @@
|
||||
.co-notice { display:flex; align-items:flex-start; gap:.6rem; padding:.75rem 1rem; border:1px solid #d7c39d; border-radius:.65rem; background:#fffaf0; color:#6a5129; line-height:1.55; }
|
||||
.co-notice .material-icons-outlined { color:var(--co-accent); font-size:1.15rem; }
|
||||
.co-notice.is-error { border-color:#e3b0b0; background:#fdf1f1; color:#7a1010; } .co-notice.is-error .material-icons-outlined { color:#b80000; }
|
||||
.co-hero { display:grid; grid-template-columns:minmax(0,1.4fr) minmax(18rem,1fr); gap:1rem; }
|
||||
.co-hero { display:grid; grid-template-columns:minmax(0,1.4fr) minmax(18rem,1fr); gap:1rem; align-items:start; }
|
||||
.co-card { overflow:hidden; border:1px solid var(--co-border); border-radius:.75rem; background:#fff; }
|
||||
.co-card__head { display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:.5rem 1rem; padding:.85rem 1.15rem; border-bottom:1px solid var(--co-border); }
|
||||
.co-card__title { display:flex; align-items:center; gap:.45rem; margin:0; font-size:.9rem; font-weight:700; } .co-card__title .material-icons-outlined { color:var(--co-accent); font-size:1.1rem; }
|
||||
.co-card__hint { color:var(--co-muted); font-size:.72rem; }
|
||||
.co-flow { display:grid; grid-template-columns:repeat(5,minmax(0,1fr)); gap:0; margin:0; padding:1rem 1.15rem 1.15rem; list-style:none; counter-reset:step; }
|
||||
.co-flow li { position:relative; display:grid; gap:.25rem; padding-right:.75rem; counter-increment:step; }
|
||||
.co-flow li { position:relative; display:grid; align-content:start; gap:.25rem; padding-right:.75rem; counter-increment:step; }
|
||||
.co-flow li::before { display:grid; width:1.6rem; height:1.6rem; place-items:center; border-radius:50%; background:var(--co-soft); color:var(--co-accent); font-weight:700; font-size:.72rem; content:counter(step); }
|
||||
.co-flow li:not(:last-child)::after { position:absolute; top:.8rem; left:2rem; right:.5rem; height:1px; background:var(--co-border); content:''; }
|
||||
.co-flow strong { font-size:.78rem; } .co-flow span { color:var(--co-muted); font-size:.7rem; line-height:1.5; }
|
||||
@ -43,6 +43,10 @@
|
||||
.co-field input:focus, .co-field select:focus { border-color:var(--co-accent); outline:none; box-shadow:0 0 0 3px rgba(133,102,50,.18); }
|
||||
.co-help { color:var(--co-muted); font-size:.68rem; line-height:1.5; } .co-error { color:#b80000; font-size:.72rem; }
|
||||
.co-invite__row { display:grid; grid-template-columns:minmax(0,1fr) 7rem; gap:.6rem; }
|
||||
.co-hero__main { display:grid; gap:1rem; align-content:start; min-width:0; }
|
||||
.co-profile-grid { display:grid; grid-template-columns:repeat(3, minmax(0,1fr)); gap:.7rem .8rem; padding:1rem 1.15rem 1.15rem; }
|
||||
@media (max-width: 1100px) { .co-profile-grid { grid-template-columns:repeat(2, minmax(0,1fr)); } }
|
||||
@media (max-width: 560px) { .co-profile-grid { grid-template-columns:1fr; } }
|
||||
.co-button { display:inline-flex; align-items:center; justify-content:center; gap:.35rem; height:2.2rem; padding:0 .8rem; border:1px solid var(--co-border); border-radius:.45rem; background:#fff; color:var(--co-ink); font:inherit; font-weight:600; text-decoration:none; white-space:nowrap; cursor:pointer; }
|
||||
.co-button .material-icons-outlined { font-size:1rem; } .co-button--primary { border-color:var(--co-accent); background:var(--co-accent); color:#fff; } .co-button--primary:hover { background:#6a5129; }
|
||||
.co-toolbar { display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:.75rem; padding:.75rem 1.15rem; border-bottom:1px solid var(--co-border); background:#fffdf8; }
|
||||
@ -79,19 +83,45 @@
|
||||
@endif
|
||||
|
||||
<div class="co-hero">
|
||||
<div class="co-hero__main">
|
||||
<div class="co-card">
|
||||
<div class="co-card__head">
|
||||
<h2 class="co-card__title"><span class="material-icons-outlined" aria-hidden="true">route</span>入驻流程</h2>
|
||||
<span class="co-card__hint">快递方无需账号,扫码即可填写</span>
|
||||
</div>
|
||||
<ol class="co-flow">
|
||||
<li><strong>生成二维码</strong><span>右侧填个备注,生成后发给快递方</span></li>
|
||||
<li><strong>生成二维码</strong><span>填快递公司代码、系统快递名称和快递资料,生成后发给快递方</span></li>
|
||||
<li><strong>快递扫码填写</strong><span>主体、联系人、结算账户、报价、资质照片</span></li>
|
||||
<li><strong>对接人初审</strong><span>资料不全可退回,快递用原码补件</span></li>
|
||||
<li><strong>财务复审</strong><span>确认系统快递名称,首版报价进报价管理</span></li>
|
||||
<li><strong>签署并开通</strong><span>协议签署后开通,进快递资料「入驻快递」</span></li>
|
||||
<li><strong>签署并开通</strong><span>协议签署后开通,信息对齐到快递资料</span></li>
|
||||
</ol>
|
||||
</div>
|
||||
<section class="co-card" aria-labelledby="co-profile-title">
|
||||
<div class="co-card__head">
|
||||
<h2 class="co-card__title" id="co-profile-title"><span class="material-icons-outlined" aria-hidden="true">local_shipping</span>快递资料</h2>
|
||||
<span class="co-card__hint">全部必填 · 我方填写,快递方看不到;生成后对齐到快递资料,入驻详情里也能改</span>
|
||||
</div>
|
||||
<div class="co-profile-grid">
|
||||
@foreach (\App\Models\Business\CourierOnboarding::PROFILE_FIELDS as $field => [$label, $options])
|
||||
<div class="co-field">
|
||||
<label for="co-{{ $field }}">{{ $label }} *</label>
|
||||
@if ($options !== null)
|
||||
<select id="co-{{ $field }}" name="{{ $field }}" form="invite" required>
|
||||
<option value=""></option>
|
||||
@foreach ($options as $option)
|
||||
<option value="{{ $option }}" @selected(old($field) === $option)>{{ $option }}</option>
|
||||
@endforeach
|
||||
</select>
|
||||
@else
|
||||
<input id="co-{{ $field }}" name="{{ $field }}" form="invite" required type="{{ $field === 'courier_email' ? 'email' : 'text' }}" maxlength="{{ $field === 'network_code' ? 64 : 191 }}" value="{{ old($field) }}" placeholder="{{ ['courier_email' => '如:kefu@example.com', 'network_code' => '如:519001', 'network_region' => '如:江苏省常州市天宁区'][$field] ?? '' }}" autocomplete="off">
|
||||
@endif
|
||||
@error($field)<span class="co-error">{{ $message }}</span>@enderror
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<form class="co-card" id="invite" method="POST" action="{{ route('business.courier-onboardings.store') }}">
|
||||
@csrf
|
||||
<div class="co-card__head">
|
||||
@ -147,7 +177,7 @@
|
||||
<div class="co-table-wrap">
|
||||
<table class="co-table" aria-label="入驻申请">
|
||||
<thead>
|
||||
<tr><th>入驻单号</th><th>状态</th><th>备注</th><th>类型</th><th>公司 / 姓名</th><th>网点 / 品牌</th><th>对接人</th><th>系统快递名称</th><th>附件</th><th>提交时间</th><th>最近更新</th><th>操作</th></tr>
|
||||
<tr><th>入驻单号</th><th>状态</th><th>备注</th><th>类型</th><th>公司 / 姓名</th><th>网点 / 品牌</th><th>快递公司代码</th>@foreach (\App\Models\Business\CourierOnboarding::PROFILE_FIELDS as [$profileLabel])<th>{{ $profileLabel }}</th>@endforeach<th>对接人</th><th>系统快递名称</th><th>附件</th><th>提交时间</th><th>最近更新</th><th>操作</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse ($rows ?? [] as $row)
|
||||
@ -158,6 +188,10 @@
|
||||
<td>{{ $row->company_full_name ? $row->entityLabel() : '—' }}</td>
|
||||
<td class="is-clamp" title="{{ $row->company_full_name }}">{{ $row->company_full_name ?: '—' }}</td>
|
||||
<td>{{ $row->network_name ?: '—' }}{{ $row->carrier_brand ? ' · ' . $row->carrier_brand : '' }}</td>
|
||||
<td class="is-code">{{ $row->workplatform_expcode ?: '—' }}</td>
|
||||
@foreach (array_keys(\App\Models\Business\CourierOnboarding::PROFILE_FIELDS) as $profileField)
|
||||
<td class="is-clamp" title="{{ $row->{$profileField} }}">{{ $row->{$profileField} ?: '—' }}</td>
|
||||
@endforeach
|
||||
<td>{{ $row->contact_name ?: '—' }}{{ $row->contact_phone ? ' ' . $row->contact_phone : '' }}</td>
|
||||
<td>{{ $row->courier_name ?: '—' }}</td>
|
||||
<td class="is-code">{{ $row->files_count }}</td>
|
||||
@ -166,7 +200,7 @@
|
||||
<td><a href="{{ route('business.courier-onboardings.show', $row) }}">{{ in_array($row->status, ['submitted', 'first_approved', 'approved'], true) ? '去处理' : '查看' }}</a></td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr><td colspan="12" class="co-empty">{{ $search !== '' ? '没有符合条件的入驻申请。' : '这里还没有入驻申请,先在上方生成一个二维码发给快递方。' }}</td></tr>
|
||||
<tr><td colspan="24" class="co-empty">{{ $search !== '' ? '没有符合条件的入驻申请。' : '这里还没有入驻申请,先在上方生成一个二维码发给快递方。' }}</td></tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
<td class="is-onboarding">{{ $onb->statusLabel() }}</td>
|
||||
<td class="is-onboarding">
|
||||
@if (($info['erp_status'] ?? '') === 'pending')
|
||||
<span class="courier-overview-tag is-warn" title="等 ERP 专员在钉钉发起「新建快递」流程,完结后自动补齐">待 ERP 开通</span>
|
||||
<span class="courier-overview-tag is-warn" title="ERP 专员开通发货系统账号后,在入驻详情「ERP 开通」里补录 ERP账户ID">待 ERP 开通</span>
|
||||
@elseif (($info['erp_status'] ?? '') === 'opened')
|
||||
<span class="courier-overview-tag is-ok">已开通</span>
|
||||
@else
|
||||
@ -15,8 +15,11 @@
|
||||
@endif
|
||||
</td>
|
||||
<td class="is-onboarding is-clamped" title="{{ $onb->company_full_name }}">{{ $onb->entityLabel() }} · {{ $onb->company_full_name ?: '-' }}</td>
|
||||
@foreach (\App\Business\CourierProfileData::APPENDED_PROFILE_FIELDS as $profileField)
|
||||
<td class="is-onboarding is-clamped" title="{{ $onb->{$profileField} }}">{{ $onb->{$profileField} ?: '-' }}</td>
|
||||
@endforeach
|
||||
<td class="is-onboarding">@if ($info['missing_files'] ?? [])<span class="courier-overview-tag is-warn" title="{{ implode('、', $info['missing_files']) }}">缺 {{ count($info['missing_files']) }} 项</span>@else<span class="courier-overview-tag is-ok">齐全</span>@endif</td>
|
||||
<td class="is-onboarding is-code">{{ $info['effective_version'] ?? '-' }}</td>
|
||||
@else
|
||||
<td class="is-onboarding" colspan="6"><span class="courier-overview-sub">未入驻</span>@if (! empty($platformName)) · <a href="{{ route('business.pages.show', ['section' => 'courier-payables', 'page' => 'courier-onboarding', 'courier_name' => $platformName, 'expcode' => $platformCode ?? null]) }}#invite" title="给这家快递发入驻二维码,补齐主体、账户、证照">发码补资料</a>@endif</td>
|
||||
<td class="is-onboarding" colspan="{{ 6 + count(\App\Business\CourierProfileData::APPENDED_PROFILE_FIELDS) }}"><span class="courier-overview-sub">未入驻</span>@if (! empty($platformName)) · <a href="{{ route('business.pages.show', ['section' => 'courier-payables', 'page' => 'courier-onboarding', 'courier_name' => $platformName, 'expcode' => $platformCode ?? null]) }}#invite" title="给这家快递发入驻二维码,补齐主体、账户、证照">发码补资料</a>@endif</td>
|
||||
@endif
|
||||
|
||||
@ -99,7 +99,7 @@
|
||||
<div><div class="quote-change-panel__title" id="quote-source-title"><span class="material-icons-outlined" aria-hidden="true">source</span><span>第一步:选择原报价</span></div><div class="quote-change-panel__hint">原报价保持只读,系统只保存发生变化的单元格。</div></div>
|
||||
</header>
|
||||
<div class="quote-change-panel__body">
|
||||
<form class="quote-change-source" method="GET" action="{{ route('business.courier-quote-changes.create') }}">
|
||||
<form class="quote-change-source" method="GET" action="{{ route('business.courier-quote-changes.start') }}">
|
||||
<div class="quote-change-field"><label for="source_quote_id">报价版本</label><select class="quote-change-control" id="source_quote_id" name="source_quote_id">@foreach ($quotes as $quote)<option value="{{ $quote['id'] }}" @selected($quote['id'] === $source['id'])>{{ $quote['id'] }} · {{ $quote['company_name'] }} · {{ $quote['quote_type'] }}</option>@endforeach</select></div>
|
||||
<button class="quote-change-button" type="submit"><span class="material-icons-outlined" aria-hidden="true">sync_alt</span><span>载入报价</span></button>
|
||||
</form>
|
||||
|
||||
@ -35,7 +35,7 @@
|
||||
<main class="quote-history">
|
||||
<div class="quote-history__top">
|
||||
<a class="quote-history__back" href="{{ route('business.pages.show', ['section'=>'courier-payables','page'=>'quote-management']) }}"><span class="material-icons-outlined" aria-hidden="true" style="font-size:16px">arrow_back</span><span>返回报价管理</span></a>
|
||||
<div class="quote-history__actions"><a class="quote-history__button quote-history__button--primary" href="{{ route('business.courier-quote-changes.create') }}"><span class="material-icons-outlined" aria-hidden="true">edit_note</span><span>发起报价变更</span></a></div>
|
||||
<div class="quote-history__actions"><span class="quote-history__hint">变价请在报价管理的报价列表里,点对应报价那一行的「变价」。</span></div>
|
||||
</div>
|
||||
@if(is_string(session('success')))<div style="margin-bottom:16px;border:1px solid #BAD0AB;border-radius:8px;background:#F3F8EF;padding:10px 12px;color:#40622F" role="status">{{ session('success') }}</div>@endif
|
||||
<section class="quote-history__panel" aria-labelledby="quote-history-title">
|
||||
|
||||
@ -775,10 +775,6 @@
|
||||
<span class="material-icons-outlined" aria-hidden="true">history</span>
|
||||
<span>报价历史</span>
|
||||
</a>
|
||||
<a class="quote-button quote-button--primary" href="{{ route('business.courier-quote-changes.create') }}" title="创建并保存报价变更草稿">
|
||||
<span class="material-icons-outlined" aria-hidden="true">edit_note</span>
|
||||
<span>发起报价变更</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1028,7 +1024,7 @@
|
||||
action.setAttribute('aria-label', '查看 ' + quote.sheet_name);
|
||||
actionCell.appendChild(action);
|
||||
var changeAction = create('a', 'quote-action', '变价');
|
||||
changeAction.href = quote.requote_url || (@json(route('business.courier-quote-changes.create')) + '?source_quote_id=' + encodeURIComponent(quote.id));
|
||||
changeAction.href = quote.requote_url || (@json(route('business.courier-quote-changes.start')) + '?source_quote_id=' + encodeURIComponent(quote.id));
|
||||
changeAction.title = '发起 ' + quote.sheet_name + ' 的变更草稿';
|
||||
changeAction.setAttribute('aria-label', '变价 ' + quote.sheet_name);
|
||||
if (quote.status !== '已作废') {
|
||||
|
||||
@ -129,6 +129,8 @@ Route::prefix('workspace/courier-payables/quote-management/changes')
|
||||
->group(function () {
|
||||
Route::get('/', [CourierQuoteChanges::class, 'index'])->name('index');
|
||||
Route::get('create', [CourierQuoteChanges::class, 'create'])->name('create');
|
||||
// 不以 create 结尾:Akaunting 的套餐限制中间件会把 …/create 的 GET 请求跳到用户页。
|
||||
Route::get('new', [CourierQuoteChanges::class, 'create'])->name('start');
|
||||
Route::post('/', [CourierQuoteChanges::class, 'store'])->name('store');
|
||||
Route::get('{quoteChange}', [CourierQuoteChanges::class, 'show'])->name('show');
|
||||
Route::get('{quoteChange}/edit', [CourierQuoteChanges::class, 'edit'])->name('edit');
|
||||
|
||||
@ -42,6 +42,7 @@ class CourierOnboardingWorkflowTest extends FeatureTestCase
|
||||
->assertSessionHasErrors('courier_name');
|
||||
|
||||
$response = $this->loginAs()->post(route('business.courier-onboardings.store'), [
|
||||
...self::profile(),
|
||||
'courier_name' => '新北中通',
|
||||
'workplatform_expcode' => 'xbzt',
|
||||
'invite_label' => '新北中通 · 张经理',
|
||||
@ -54,16 +55,16 @@ class CourierOnboardingWorkflowTest extends FeatureTestCase
|
||||
|
||||
// 系统快递名称不能和其他进行中的入驻重复。
|
||||
$this->withExceptionHandling()->loginAs()
|
||||
->post(route('business.courier-onboardings.store'), ['courier_name' => '新北中通', 'workplatform_expcode' => 'NEW1'])
|
||||
->post(route('business.courier-onboardings.store'), [...self::profile(), 'courier_name' => '新北中通', 'workplatform_expcode' => 'NEW1'])
|
||||
->assertSessionHasErrors('courier_name');
|
||||
|
||||
// 快递公司代码必填、自动转大写、不能和其他入驻重复。
|
||||
$this->assertSame('XBZT', $onboarding->workplatform_expcode);
|
||||
$this->withExceptionHandling()->loginAs()
|
||||
->post(route('business.courier-onboardings.store'), ['courier_name' => '另一家'])
|
||||
->post(route('business.courier-onboardings.store'), [...self::profile(), 'courier_name' => '另一家'])
|
||||
->assertSessionHasErrors('workplatform_expcode');
|
||||
$this->withExceptionHandling()->loginAs()
|
||||
->post(route('business.courier-onboardings.store'), ['courier_name' => '另一家', 'workplatform_expcode' => 'XBZT'])
|
||||
->post(route('business.courier-onboardings.store'), [...self::profile(), 'courier_name' => '另一家', 'workplatform_expcode' => 'XBZT'])
|
||||
->assertSessionHasErrors('workplatform_expcode');
|
||||
$this->assertSame(CourierOnboarding::STATUS_INVITED, $onboarding->status);
|
||||
$this->assertSame(40, strlen($onboarding->token));
|
||||
@ -954,7 +955,7 @@ class CourierOnboardingWorkflowTest extends FeatureTestCase
|
||||
->assertOk()
|
||||
->assertSee('value="老极兔"', false)
|
||||
->assertSee('value="JT03"', false);
|
||||
$this->loginAs()->post(route('business.courier-onboardings.store'), ['courier_name' => '老极兔', 'workplatform_expcode' => 'JT03']);
|
||||
$this->loginAs()->post(route('business.courier-onboardings.store'), [...self::profile(), 'courier_name' => '老极兔', 'workplatform_expcode' => 'JT03']);
|
||||
$this->assertSame('JT03', CourierOnboarding::query()->latest('id')->value('workplatform_expcode'));
|
||||
}
|
||||
|
||||
@ -1122,10 +1123,69 @@ class CourierOnboardingWorkflowTest extends FeatureTestCase
|
||||
$this->travelBack();
|
||||
}
|
||||
|
||||
public function test_invite_profile_fields_are_optional_and_align_to_courier_information(): void
|
||||
{
|
||||
$this->withExceptionHandling()->loginAs()
|
||||
->post(route('business.courier-onboardings.store'), [...self::profile(), 'courier_name' => '新快递十', 'workplatform_expcode' => 'XKD10', 'courier_category' => '乱填'])
|
||||
->assertSessionHasErrors('courier_category');
|
||||
$this->loginAs()->post(route('business.courier-onboardings.store'), [
|
||||
'courier_name' => '新快递十', 'workplatform_expcode' => 'XKD10',
|
||||
'courier_category' => '外采快递', 'cooperation_mode' => '保丢不保损', 'courier_attribute' => '工厂',
|
||||
'deduction_method' => '损耗+运费', 'waybill_type' => '手填单号', 'courier_email' => 'kf@example.com',
|
||||
'need_logistics_check' => '是', 'shipping_mode' => '一单多货', 'workplatform_account' => '新开',
|
||||
'network_code' => '519001', 'network_region' => '江苏省常州市天宁区',
|
||||
])->assertSessionHasNoErrors();
|
||||
$onboarding = CourierOnboarding::query()->where('workplatform_expcode', 'XKD10')->firstOrFail();
|
||||
$this->assertSame(['外采快递', '损耗+运费', '519001'], [$onboarding->courier_category, $onboarding->deduction_method, $onboarding->network_code]);
|
||||
|
||||
// 快递资料全部必填。
|
||||
$this->withExceptionHandling()->loginAs()->post(route('business.courier-onboardings.store'), ['courier_name' => '新快递十一', 'workplatform_expcode' => 'XKD11'])
|
||||
->assertSessionHasErrors(['courier_category' => '请选择快递类型。', 'network_region' => '请填写网点所在地区。']);
|
||||
$this->assertFalse(CourierOnboarding::query()->where('workplatform_expcode', 'XKD11')->exists());
|
||||
// 详情里修改时不能清空。
|
||||
$this->withExceptionHandling()->loginAs()->post(route('business.courier-onboardings.internal', CourierOnboarding::query()->where('workplatform_expcode', 'XKD10')->firstOrFail()), ['courier_email' => ''])
|
||||
->assertSessionHasErrors('courier_email');
|
||||
|
||||
$this->loginAs()->get(route('business.pages.show', ['section' => 'courier-payables', 'page' => 'courier-onboarding', 'group' => 'all']))
|
||||
->assertOk()->assertSeeText('快递合作方式')->assertSeeText('保丢不保损')->assertSeeText('XKD10');
|
||||
|
||||
// 详情页可改;只改名称/对账人的旧表单不会清空这些字段。
|
||||
$this->loginAs()->get(route('business.courier-onboardings.show', $onboarding))->assertOk()->assertSeeText('快递资料(我方填写)');
|
||||
$this->loginAs()->post(route('business.courier-onboardings.internal', $onboarding), ['reconciler' => '王会计'])->assertSessionHasNoErrors();
|
||||
$this->assertSame('外采快递', $onboarding->fresh()->courier_category);
|
||||
$this->assertSame('新快递十', $onboarding->fresh()->courier_name);
|
||||
$this->loginAs()->post(route('business.courier-onboardings.internal', $onboarding), ['shipping_mode' => '一单一货'])->assertSessionHasNoErrors();
|
||||
$this->assertSame(['一单一货', '王会计', '新快递十'], [$onboarding->fresh()->shipping_mode, $onboarding->fresh()->reconciler, $onboarding->fresh()->courier_name]);
|
||||
|
||||
// 快递资料:扣款方式对齐到左侧列,其余接在右侧,网点进网点明细。
|
||||
$mirror = \Mockery::mock(\Modules\EcommerceFinance\Repositories\CourierInformationMirrorRepository::class)->shouldIgnoreMissing();
|
||||
$mirror->shouldReceive('relatedAvailability')->andReturn([]);
|
||||
app()->instance(\Modules\EcommerceFinance\Repositories\CourierInformationMirrorRepository::class, $mirror);
|
||||
$this->loginAs()->get(route('business.pages.show', ['section' => 'courier-payables', 'page' => 'courier-information', 'selected' => 'XKD10', 'detail_tab' => 'networks']))
|
||||
->assertOk()
|
||||
->assertSee('<th>扣款方式</th>', false)
|
||||
->assertSeeText('损耗+运费')
|
||||
->assertSee('<th class="is-onboarding">快递合作方式</th>', false)
|
||||
->assertSeeText('kf@example.com')
|
||||
->assertSeeText('519001')
|
||||
->assertSeeText('江苏省常州市天宁区');
|
||||
}
|
||||
|
||||
/** 生成二维码时必填的快递资料。 */
|
||||
private static function profile(): array
|
||||
{
|
||||
return [
|
||||
'courier_category' => '内采快递', 'cooperation_mode' => '保丢保损', 'courier_attribute' => '简尚',
|
||||
'deduction_method' => '运费', 'waybill_type' => '系统对接', 'courier_email' => 'courier@example.com',
|
||||
'need_logistics_check' => '否', 'shipping_mode' => '一单一货', 'workplatform_account' => '已有',
|
||||
'network_code' => 'N001', 'network_region' => '江苏省常州市',
|
||||
];
|
||||
}
|
||||
|
||||
private function invite(): CourierOnboarding
|
||||
{
|
||||
$this->loginAs()->post(route('business.courier-onboardings.store'), [
|
||||
'courier_name' => '新北中通-' . uniqid(), 'workplatform_expcode' => 'XB' . uniqid(), 'invite_label' => '张经理', 'valid_days' => 30,
|
||||
...self::profile(), 'courier_name' => '新北中通-' . uniqid(), 'workplatform_expcode' => 'XB' . uniqid(), 'invite_label' => '张经理', 'valid_days' => 30,
|
||||
]);
|
||||
|
||||
return CourierOnboarding::query()->latest('id')->firstOrFail();
|
||||
|
||||
@ -132,9 +132,9 @@ class QuoteManagementPageTest extends FeatureTestCase
|
||||
->assertSeeText('快递公司')
|
||||
->assertSeeText('资料状态')
|
||||
->assertSeeText('报价历史')
|
||||
->assertSeeText('发起报价变更')
|
||||
->assertDontSeeText('发起报价变更')
|
||||
->assertSee(route('business.courier-quote-changes.index'), false)
|
||||
->assertSee(route('business.courier-quote-changes.create'), false)
|
||||
->assertDontSee(route('business.courier-quote-changes.create'), false)
|
||||
->assertDontSee('data-quote-change-modal', false)
|
||||
->assertDontSeeText('只生成浏览器会话内的草稿提示')
|
||||
->assertSee('<option value="新北中通">新北中通</option>', false)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user