feat: 供应商负数预警展示采购人员 (#734)
按供应商名称批量匹配供应商管理中的采购人员,并在负数原因后展示。 Co-authored-by: 苏木 <594326199@qq.com> Co-committed-by: 苏木 <594326199@qq.com>
This commit is contained in:
parent
780775da3d
commit
6eae3c6da5
@ -141,7 +141,7 @@ class SupplierManagementMirrorRepository
|
||||
return $this->mirror->connection()->table($this->datasets->get(self::DATASET)->targetTable())
|
||||
->whereIn('scmname', $names)
|
||||
->orderBy('Id')
|
||||
->get(['Id', 'scmcode', 'scmname'])
|
||||
->get(['Id', 'scmcode', 'scmname', 'buyer'])
|
||||
->all();
|
||||
}
|
||||
|
||||
|
||||
@ -4,8 +4,10 @@ namespace Modules\EcommerceFinance\View;
|
||||
|
||||
use App\Http\Controllers\Business\PayablesFinalActions;
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Modules\EcommerceFinance\Repositories\SupplierManagementMirrorRepository;
|
||||
use Modules\EcommerceFinance\Services\PayablesFinalRegistry;
|
||||
use Modules\EcommerceFinance\Services\SupplierPayableOverrideStore;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* 供应商负数预警:直接读取「供应商应付(终版)→ 供应商应付表」,
|
||||
@ -20,6 +22,7 @@ class SupplierNegativeAlertPageData
|
||||
public function __construct(
|
||||
private readonly SupplierPayableOverrideStore $store,
|
||||
private readonly PayablesFinalRegistry $registry,
|
||||
private readonly SupplierManagementMirrorRepository $supplierManagement,
|
||||
) {
|
||||
}
|
||||
|
||||
@ -110,19 +113,59 @@ class SupplierNegativeAlertPageData
|
||||
$total = count($negativeRows);
|
||||
$pages = max((int) ceil($total / self::PER_PAGE), 1);
|
||||
$page = min(max((int) request()->query('page', 1), 1), $pages);
|
||||
$items = array_map(
|
||||
static fn (array $row): object => (object) $row,
|
||||
array_slice($negativeRows, ($page - 1) * self::PER_PAGE, self::PER_PAGE),
|
||||
$pageRows = array_slice($negativeRows, ($page - 1) * self::PER_PAGE, self::PER_PAGE);
|
||||
$pageSupplierNames = array_values(array_unique(array_filter(
|
||||
array_map(
|
||||
static fn (array $row): string => trim((string) ($row['supplier'] ?? '')),
|
||||
$pageRows,
|
||||
),
|
||||
static fn (string $name): bool => $name !== '',
|
||||
)));
|
||||
$purchasersBySupplier = [];
|
||||
if ($pageSupplierNames !== []) {
|
||||
try {
|
||||
foreach ($this->supplierManagement->suppliersByNames($pageSupplierNames) as $supplier) {
|
||||
$name = trim((string) ($supplier->scmname ?? ''));
|
||||
$buyer = trim((string) ($supplier->buyer ?? ''));
|
||||
if ($name !== '' && $buyer !== '') {
|
||||
$purchasersBySupplier[$name][$buyer] = true;
|
||||
}
|
||||
}
|
||||
} catch (Throwable $exception) {
|
||||
report($exception);
|
||||
}
|
||||
}
|
||||
$purchasersBySupplier = array_map(
|
||||
static fn (array $buyers): string => implode('、', array_keys($buyers)),
|
||||
$purchasersBySupplier,
|
||||
);
|
||||
$items = array_map(
|
||||
static function (array $row) use ($purchasersBySupplier): object {
|
||||
$supplier = trim((string) ($row['supplier'] ?? ''));
|
||||
$row['purchaser'] = $purchasersBySupplier[$supplier] ?? '';
|
||||
|
||||
return (object) $row;
|
||||
},
|
||||
$pageRows,
|
||||
);
|
||||
|
||||
$negativeAlertFields = [];
|
||||
$fields = collect($this->registry->fields(
|
||||
PayablesFinalRegistry::SECTION_SUPPLIER,
|
||||
self::DATASET,
|
||||
))->map(
|
||||
static fn (array $definition, string $name): array => ['name' => $name] + $definition,
|
||||
)->values()->all();
|
||||
foreach ($fields as $field) {
|
||||
$negativeAlertFields[] = $field;
|
||||
if (($field['name'] ?? '') === 'negative_reason') {
|
||||
$negativeAlertFields[] = ['name' => 'purchaser', 'label' => '采购', 'type' => 'text'];
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'view' => 'business.pages.negative-alerts.supplier-negative-alert',
|
||||
'negativeAlertFields' => collect($this->registry->fields(
|
||||
PayablesFinalRegistry::SECTION_SUPPLIER,
|
||||
self::DATASET,
|
||||
))->map(
|
||||
static fn (array $definition, string $name): array => ['name' => $name] + $definition,
|
||||
)->values()->all(),
|
||||
'negativeAlertFields' => $negativeAlertFields,
|
||||
'negativeAlertRows' => new LengthAwarePaginator(
|
||||
$items,
|
||||
$total,
|
||||
|
||||
@ -6,6 +6,7 @@ use App\Http\Controllers\Business\PayablesFinalActions;
|
||||
use App\Listeners\Menu\ShowInAdmin;
|
||||
use App\Models\Auth\Permission;
|
||||
use App\Utilities\BusinessNavigation;
|
||||
use Modules\EcommerceFinance\Repositories\SupplierManagementMirrorRepository;
|
||||
use Modules\EcommerceFinance\Services\PayablesFinalRegistry;
|
||||
use Modules\EcommerceFinance\Services\SupplierPayableOverrideStore;
|
||||
use Tests\Feature\FeatureTestCase;
|
||||
@ -57,6 +58,17 @@ class NegativeAlertPagesTest extends FeatureTestCase
|
||||
'should_pay' => '-500.00',
|
||||
'estimated_price' => '50.00',
|
||||
]);
|
||||
$supplierManagement = \Mockery::mock(SupplierManagementMirrorRepository::class);
|
||||
$supplierManagement->shouldReceive('suppliersByNames')
|
||||
->once()
|
||||
->withArgs(static fn (array $names): bool => count($names) === 2
|
||||
&& in_array('负余额供应商', $names, true)
|
||||
&& in_array('公式命中供应商', $names, true))
|
||||
->andReturn([
|
||||
(object) ['scmname' => '负余额供应商', 'buyer' => '采购甲'],
|
||||
(object) ['scmname' => '公式命中供应商', 'buyer' => '采购乙'],
|
||||
]);
|
||||
$this->app->instance(SupplierManagementMirrorRepository::class, $supplierManagement);
|
||||
|
||||
$response = $this->loginAs()
|
||||
->get(route('business.pages.show', [
|
||||
@ -72,6 +84,8 @@ class NegativeAlertPagesTest extends FeatureTestCase
|
||||
->assertSeeText('公式命中供应商')
|
||||
->assertSeeText('-128.50')
|
||||
->assertSeeText('历史多付款')
|
||||
->assertSeeText('采购甲')
|
||||
->assertSeeText('采购乙')
|
||||
->assertDontSeeText('正余额供应商')
|
||||
->assertDontSeeText('负余额但公式为正供应商');
|
||||
|
||||
@ -81,7 +95,16 @@ class NegativeAlertPagesTest extends FeatureTestCase
|
||||
);
|
||||
$html = (string) $response->getContent();
|
||||
preg_match_all('/<th(?:\s|>)/', $html, $headers);
|
||||
$this->assertCount(count($fields), $headers[0]);
|
||||
// 序号 + 隐藏主体名称后的原字段 + 动态匹配的采购。
|
||||
$this->assertCount(count($fields) + 1, $headers[0]);
|
||||
preg_match_all('/<th[^>]*>(.*?)<\/th>/s', $html, $headerMatches);
|
||||
$labels = array_map(
|
||||
static fn (string $label): string => trim(html_entity_decode(strip_tags($label), ENT_QUOTES | ENT_HTML5, 'UTF-8')),
|
||||
$headerMatches[1],
|
||||
);
|
||||
$negativeReasonIndex = array_search('负数原因', $labels, true);
|
||||
$this->assertNotFalse($negativeReasonIndex);
|
||||
$this->assertSame('采购', $labels[$negativeReasonIndex + 1]);
|
||||
$this->assertStringNotContainsString('供应商公司主体名称', $html);
|
||||
$this->assertStringNotContainsString('测试供应商有限公司', $html);
|
||||
|
||||
|
||||
@ -157,14 +157,15 @@ class SupplierManagementMirrorRepositoryTest extends TestCase
|
||||
{
|
||||
$this->ready(SupplierManagementMirrorRepository::DATASET);
|
||||
$this->table('js_supplier_management')->insert([
|
||||
['Id' => 9, 'scmcode' => 'N901', 'scmname' => '一泰'],
|
||||
['Id' => 11, 'scmcode' => 'Y411', 'scmname' => '七彩'],
|
||||
['Id' => 9, 'scmcode' => 'N901', 'scmname' => '一泰', 'buyer' => '采购甲'],
|
||||
['Id' => 11, 'scmcode' => 'Y411', 'scmname' => '七彩', 'buyer' => '采购乙'],
|
||||
]);
|
||||
|
||||
$rows = $this->repository->suppliersByNames(['一泰', '不存在']);
|
||||
|
||||
$this->assertCount(1, $rows);
|
||||
$this->assertSame('N901', $rows[0]->scmcode);
|
||||
$this->assertSame('采购甲', $rows[0]->buyer);
|
||||
}
|
||||
|
||||
private function ready(string $key): void
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user