203 lines
9.4 KiB
PHP
203 lines
9.4 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature\Business;
|
|
|
|
use App\Models\Auth\Permission;
|
|
use Illuminate\Validation\ValidationException;
|
|
use Modules\EcommerceFinance\Services\PayablesUnpricedCycleProcessor;
|
|
use Modules\EcommerceFinance\Services\SupplierPayableOverrideStore;
|
|
use Tests\Feature\FeatureTestCase;
|
|
|
|
class PayablesUnpricedCycleTest extends FeatureTestCase
|
|
{
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
$this->user->attachPermission(
|
|
Permission::where('name', 'read-admin-panel')->firstOrFail()
|
|
);
|
|
}
|
|
|
|
public function test_cycle_matches_history_before_carrying_in_new_unpriced_rows(): void
|
|
{
|
|
$store = app(SupplierPayableOverrideStore::class);
|
|
$companyId = (int) $this->company->id;
|
|
$userId = (int) $this->user->id;
|
|
|
|
$store->saveBatch(PayablesUnpricedCycleProcessor::DELIVERY_HISTORY_DATASET, [
|
|
'id:history:delivery:matched-1' => [
|
|
'supplier' => '供应商甲', 'barCode' => 'M-1', 'qty' => '2', 'unitPrice' => null, 'amount' => null,
|
|
],
|
|
'id:history:delivery:matched-2' => [
|
|
'supplier' => '供应商甲', 'barCode' => 'M-1', 'qty' => '3', 'unitPrice' => null, 'amount' => null,
|
|
],
|
|
'id:history:delivery:unmatched' => [
|
|
'supplier' => '供应商乙', 'barCode' => 'NO-PRICE', 'qty' => '4', 'unitPrice' => null, 'amount' => null,
|
|
],
|
|
], $companyId, $userId, 'test');
|
|
|
|
$store->saveBatch(PayablesUnpricedCycleProcessor::RETURN_HISTORY_DATASET, [
|
|
'id:history:return:matched' => [
|
|
'supplier' => '退货甲', 'barcode' => 'R-1', 'qty' => '3', 'unit_price' => null, 'amount' => null,
|
|
],
|
|
'id:history:return:unmatched' => [
|
|
'supplier' => '退货乙', 'barcode' => 'NO-PRICE', 'qty' => '5', 'unit_price' => null, 'amount' => null,
|
|
],
|
|
], $companyId, $userId, 'test');
|
|
|
|
$store->saveBatch(PayablesUnpricedCycleProcessor::DELIVERY_RECONCILIATION_DATASET, [
|
|
'id:recon:delivery:new' => [
|
|
'summary_month' => '2026-10', 'purchaseNo' => 'CG-NEW', 'stockNo' => 'RK-NEW',
|
|
'productCode' => 'NEW-D', 'qty' => '2', 'amount' => '', 'guessAmount' => '50',
|
|
],
|
|
'id:recon:delivery:priced' => [
|
|
'summary_month' => '2026-10', 'purchaseNo' => 'CG-OLD', 'stockNo' => 'RK-OLD',
|
|
'productCode' => 'M-1', 'qty' => '2', 'amount' => '20', 'guessAmount' => '25',
|
|
],
|
|
], $companyId, $userId, 'test');
|
|
|
|
$store->saveBatch(PayablesUnpricedCycleProcessor::RETURN_RECONCILIATION_DATASET, [
|
|
'id:recon:return:new' => [
|
|
'summary_month' => '2026-10', 'supplier' => '退货甲', 'barcode' => 'NEW-R',
|
|
'qty' => '1', 'amount' => '', 'guess_amount' => '30',
|
|
],
|
|
'id:recon:return:priced' => [
|
|
'summary_month' => '2026-10', 'supplier' => '退货甲', 'barcode' => 'R-1',
|
|
'qty' => '1', 'amount' => '8', 'guess_amount' => '10',
|
|
],
|
|
], $companyId, $userId, 'test');
|
|
|
|
$priceFile = $this->makeFile(
|
|
'prices.csv',
|
|
"\xEF\xBB\xBF商品编码,价格类型,变价后价格,生效开始时间,生效结束时间,流程完成时间\n"
|
|
. "M-1,变价,10.50,2026-01-01,2026-09-30,\n"
|
|
. "M-1,变价,12.00,2026-10-01,,2026-10-01\n"
|
|
. "R-1,定价,8.00,2026-09-01,,\n"
|
|
. "OLD,变价,99.00,2026-01-01,2026-09-30,\n",
|
|
);
|
|
|
|
try {
|
|
$result = app(PayablesUnpricedCycleProcessor::class)->process(
|
|
$priceFile,
|
|
'2026-10',
|
|
'2026-11-02',
|
|
$companyId,
|
|
$userId,
|
|
);
|
|
} finally {
|
|
@unlink($priceFile);
|
|
}
|
|
|
|
$this->assertSame(2, $result['matched_delivery_rows']);
|
|
$this->assertSame(1, $result['matched_return_rows']);
|
|
$this->assertSame(1, $result['new_delivery_rows']);
|
|
$this->assertSame(1, $result['new_return_rows']);
|
|
|
|
$pricedDelivery = $store->listRows(PayablesUnpricedCycleProcessor::DELIVERY_PRICED_DATASET, $companyId);
|
|
$pricedReturn = $store->listRows(PayablesUnpricedCycleProcessor::RETURN_PRICED_DATASET, $companyId);
|
|
$this->assertCount(2, $pricedDelivery);
|
|
$this->assertCount(1, $pricedReturn);
|
|
$this->assertSame('12', $pricedDelivery[0]['unitPrice']);
|
|
$this->assertSame('24.00', $pricedDelivery[0]['amount']);
|
|
$this->assertSame('8', $pricedReturn[0]['unit_price']);
|
|
$this->assertSame('24.00', $pricedReturn[0]['amount']);
|
|
$this->assertSame('2026-10', $pricedReturn[0]['_accounting_period']);
|
|
|
|
$remainingDelivery = $store->listRows(PayablesUnpricedCycleProcessor::DELIVERY_HISTORY_DATASET, $companyId);
|
|
$remainingReturn = $store->listRows(PayablesUnpricedCycleProcessor::RETURN_HISTORY_DATASET, $companyId);
|
|
$this->assertCount(2, $remainingDelivery);
|
|
$this->assertCount(2, $remainingReturn);
|
|
$this->assertSame(['NO-PRICE', 'NEW-D'], array_column($remainingDelivery, 'barCode'));
|
|
$this->assertSame(['NO-PRICE', 'NEW-R'], array_column($remainingReturn, 'barcode'));
|
|
|
|
$again = $this->makeFile('prices-again.csv', "商品编码,变价后价格,生效开始时间\nM-1,12,2026-10-01\n");
|
|
try {
|
|
$this->expectException(ValidationException::class);
|
|
$this->expectExceptionMessage('账期 2026-10 已完成定价批次,不能重复处理。');
|
|
app(PayablesUnpricedCycleProcessor::class)->process(
|
|
$again,
|
|
'2026-10',
|
|
'2026-11-02',
|
|
$companyId,
|
|
$userId,
|
|
);
|
|
} finally {
|
|
@unlink($again);
|
|
}
|
|
}
|
|
|
|
public function test_previous_unpriced_current_priced_page_shows_two_source_tables(): void
|
|
{
|
|
$store = app(SupplierPayableOverrideStore::class);
|
|
$companyId = (int) $this->company->id;
|
|
|
|
$store->saveBatch(PayablesUnpricedCycleProcessor::DELIVERY_PRICED_DATASET, [
|
|
'id:page:delivery' => [
|
|
'barCode' => 'DELIVERY-PRICE-1', 'qty' => '2', 'unitPrice' => '10', 'amount' => '20', 'guessAmount' => '30',
|
|
'_accounting_period' => '2026-10',
|
|
],
|
|
], $companyId, (int) $this->user->id, 'test');
|
|
$store->saveBatch(PayablesUnpricedCycleProcessor::RETURN_PRICED_DATASET, [
|
|
'id:page:return' => [
|
|
'barcode' => 'RETURN-PRICE-1', 'qty' => '1', 'unit_price' => '8', 'amount' => '8', 'guess_amount' => '10',
|
|
'_accounting_period' => '2026-10',
|
|
],
|
|
], $companyId, (int) $this->user->id, 'test');
|
|
|
|
$this->loginAs()
|
|
->get(route('business.pages.show', [
|
|
'section' => 'supplier-payables-final',
|
|
'page' => 'previous-unpriced-current-priced',
|
|
'month' => '2026-10',
|
|
]))
|
|
->assertOk()
|
|
->assertSeeText('之前月未定价-本月定价')
|
|
->assertSee('data-unpriced-cycle-tab="delivery"', false)
|
|
->assertSee('data-unpriced-cycle-tab="return"', false)
|
|
->assertSeeText('规格码')
|
|
->assertSeeText('采购金额')
|
|
->assertSeeText('DELIVERY-PRICE-1')
|
|
->assertSeeText('RETURN-PRICE-1')
|
|
->assertSee('value="2026-10"', false)
|
|
->assertSee('data-cycle-summary="delivery-record-count">1</strong>', false)
|
|
->assertSee('data-cycle-summary="delivery-quantity">2.00</strong>', false)
|
|
->assertSee('data-cycle-summary="delivery-amount">¥20.00</strong>', false)
|
|
->assertSee('data-cycle-summary="return-estimated-amount">¥10.00</strong>', false)
|
|
->assertSee('>导出</span>', false);
|
|
|
|
$export = $this->loginAs()->get(route(
|
|
'business.supplier-payables-final.previous-unpriced-current-priced.export',
|
|
['month' => '2026-10'],
|
|
))->assertOk();
|
|
$path = tempnam(sys_get_temp_dir(), 'caiwu-cycle-export') . '.xlsx';
|
|
|
|
try {
|
|
file_put_contents($path, $export->streamedContent());
|
|
$spreadsheet = \PhpOffice\PhpSpreadsheet\IOFactory::load($path);
|
|
$this->assertSame(['账期汇总', '送货未定价', '退货未定价'], $spreadsheet->getSheetNames());
|
|
$summary = $spreadsheet->getSheetByName('账期汇总')->rangeToArray('A1:E3');
|
|
$this->assertSame(['类型', '记录数', '件数', '金额', '预估金额'], $summary[0]);
|
|
$this->assertSame('送货未定价', $summary[1][0]);
|
|
$this->assertSame(2.0, (float) $summary[1][2]);
|
|
$this->assertSame(20.0, (float) $summary[1][3]);
|
|
$deliveryHeader = $spreadsheet->getSheetByName('送货未定价')->rangeToArray('A1:T1')[0];
|
|
$this->assertContains('计划单号', $deliveryHeader);
|
|
$this->assertContains('预估金额', $deliveryHeader);
|
|
$returnHeader = $spreadsheet->getSheetByName('退货未定价')->rangeToArray('A1:Q1')[0];
|
|
$this->assertContains('采购金额', $returnHeader);
|
|
$spreadsheet->disconnectWorksheets();
|
|
} finally {
|
|
@unlink($path);
|
|
}
|
|
}
|
|
|
|
private function makeFile(string $name, string $content): string
|
|
{
|
|
$path = sys_get_temp_dir() . '/caiwu-cycle-test-' . bin2hex(random_bytes(6)) . '-' . $name;
|
|
file_put_contents($path, $content);
|
|
|
|
return $path;
|
|
}
|
|
}
|