188 lines
7.2 KiB
PHP
188 lines
7.2 KiB
PHP
<?php
|
||
|
||
namespace Tests\Feature\Console;
|
||
|
||
use Illuminate\Support\Facades\DB;
|
||
use Tests\Feature\FeatureTestCase;
|
||
|
||
class ImportCompanyAlipayStatementTest extends FeatureTestCase
|
||
{
|
||
public function test_imports_statement_columns_opening_balance_and_replaces_duplicate_sources(): void
|
||
{
|
||
$connection = DB::connection('business_mirror');
|
||
$connection->table('fin_accounts')->insert([
|
||
[
|
||
'company_name' => '测试人员',
|
||
'account_short' => '测试人员支付宝',
|
||
'account_no' => '18800000001',
|
||
'account_type' => '支付宝',
|
||
'current_balance' => 0,
|
||
],
|
||
[
|
||
'company_name' => '其他公司',
|
||
'account_short' => '其他支付宝',
|
||
'account_no' => '18800000000',
|
||
'account_type' => '支付宝',
|
||
'current_balance' => 0,
|
||
],
|
||
]);
|
||
$connection->table('fin_transactions')->insert([
|
||
[
|
||
'txn_date' => '2026-10-02',
|
||
'account_short' => '测试人员支付宝',
|
||
'detail' => '待替换工单',
|
||
'income' => 10,
|
||
'expense' => 0,
|
||
'source' => 'workorder',
|
||
'source_value' => '测试人员支付宝',
|
||
'row_key' => 'old-workorder-alipay',
|
||
],
|
||
[
|
||
'txn_date' => '2026-10-02',
|
||
'account_short' => '其他支付宝',
|
||
'detail' => '其他账户保留',
|
||
'income' => 20,
|
||
'expense' => 0,
|
||
'source' => 'workorder',
|
||
'source_value' => '其他支付宝',
|
||
'row_key' => 'old-other-alipay',
|
||
],
|
||
]);
|
||
$connection->table('fin_account_map')->insert([
|
||
[
|
||
'source' => 'workorder',
|
||
'source_value' => '测试人员支付宝',
|
||
'account_short' => '测试人员支付宝',
|
||
'txn_count' => 1,
|
||
'income_sum' => 10,
|
||
'expense_sum' => 0,
|
||
],
|
||
[
|
||
'source' => 'workorder',
|
||
'source_value' => '其他支付宝',
|
||
'account_short' => '其他支付宝',
|
||
'txn_count' => 1,
|
||
'income_sum' => 20,
|
||
'expense_sum' => 0,
|
||
],
|
||
]);
|
||
|
||
$file = $this->statementFile([
|
||
['2026-10-02 09:00:00', 'ALI-1', '转账', '10.00', '', '110.00', '138******01', '*甲', '10.01 甲客户'],
|
||
['2026-10-03 10:00:00', 'ALI-2', '收款', '', '5.00', '105.00', '138******02', '*乙', '10.02 乙客户'],
|
||
['2026-11-01 11:00:00', 'ALI-3', '转账', '2.00', '', '107.00', '138******03', '*丙', '10.20 丙客户'],
|
||
]);
|
||
|
||
$this->artisan('finance-ledger:import-alipay-statement', [
|
||
'path' => $file,
|
||
'--account' => '18800000001',
|
||
'--account-short' => '测试人员支付宝',
|
||
'--from' => '2026-10-01',
|
||
'--to' => '2026-11-05',
|
||
'--opening-balance' => '100.00',
|
||
'--replace-sources' => 'workorder,alipay-company',
|
||
])->assertExitCode(0);
|
||
|
||
$this->assertDatabaseMissing('fin_transactions', ['row_key' => 'old-workorder-alipay'], 'business_mirror');
|
||
$this->assertDatabaseHas('fin_transactions', ['row_key' => 'old-other-alipay'], 'business_mirror');
|
||
$this->assertDatabaseHas('fin_transactions', [
|
||
'approval_no' => 'ALI-1',
|
||
'account_short' => '测试人员支付宝',
|
||
'counterparty_info' => '138******01 / *甲',
|
||
'income' => 10,
|
||
'expense' => 0,
|
||
'balance' => 110,
|
||
'payment_remark' => '10.01 甲客户',
|
||
'source' => 'alipay-company',
|
||
], 'business_mirror');
|
||
$this->assertDatabaseHas('fin_transactions', [
|
||
'approval_no' => 'ALI-2',
|
||
'income' => 0,
|
||
'expense' => 5,
|
||
'balance' => 105,
|
||
], 'business_mirror');
|
||
$this->assertDatabaseHas('fin_account_opening', [
|
||
'account_short' => '测试人员支付宝',
|
||
'opening_date' => '2026-10-01',
|
||
'opening_balance' => 100,
|
||
], 'business_mirror');
|
||
$this->assertDatabaseHas('fin_daily_flows', [
|
||
'flow_date' => '2026-10-02',
|
||
'account_short' => '测试人员支付宝',
|
||
'opening_balance' => 100,
|
||
'inflow' => 10,
|
||
'closing_balance' => 110,
|
||
], 'business_mirror');
|
||
$this->assertDatabaseHas('fin_daily_flows', [
|
||
'flow_date' => '2026-10-03',
|
||
'account_short' => '测试人员支付宝',
|
||
'opening_balance' => 110,
|
||
'outflow' => 5,
|
||
'closing_balance' => 105,
|
||
], 'business_mirror');
|
||
$this->assertDatabaseHas('fin_daily_flows', [
|
||
'flow_date' => '2026-11-01',
|
||
'account_short' => '测试人员支付宝',
|
||
'opening_balance' => 105,
|
||
'inflow' => 2,
|
||
'closing_balance' => 107,
|
||
], 'business_mirror');
|
||
$this->assertSame(107.0, (float) $connection->table('fin_accounts')
|
||
->where('account_short', '测试人员支付宝')
|
||
->value('current_balance'));
|
||
}
|
||
|
||
/** @param list<list<string>> $rows */
|
||
private function statementFile(array $rows): string
|
||
{
|
||
$matrix = [
|
||
['#账号:18800000001'],
|
||
['#查询起始日期:2026-10-01 00:00:00查询终止日期:2026-11-05 20:45:14'],
|
||
[
|
||
'序号', '入账时间', '支付宝交易号', '支付宝流水号', '商户订单号', '账务类型',
|
||
'收入(+元)', '支出(-元)', '账户余额(元)', '对方账户', '对方名称',
|
||
'银行订单号', '商品名称', '备注', '业务基础订单号', '付款备注',
|
||
],
|
||
];
|
||
foreach ($rows as $index => $row) {
|
||
$matrix[] = [
|
||
(string) ($index + 1),
|
||
$row[0],
|
||
$row[1],
|
||
'',
|
||
'',
|
||
$row[2],
|
||
$row[3],
|
||
$row[4],
|
||
$row[5],
|
||
$row[6],
|
||
$row[7],
|
||
'',
|
||
'',
|
||
'',
|
||
'',
|
||
$row[8],
|
||
];
|
||
}
|
||
|
||
$xmlRows = '';
|
||
foreach ($matrix as $row) {
|
||
$xmlRows .= '<Row>';
|
||
foreach ($row as $value) {
|
||
$xmlRows .= '<Cell><Data ss:Type="String">'
|
||
. htmlspecialchars((string) $value, ENT_XML1 | ENT_QUOTES, 'UTF-8')
|
||
. '</Data></Cell>';
|
||
}
|
||
$xmlRows .= '</Row>';
|
||
}
|
||
$xml = '<?xml version="1.0" encoding="UTF-8"?>'
|
||
. '<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"'
|
||
. ' xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">'
|
||
. '<Worksheet ss:Name="账务组合查询1"><Table>' . $xmlRows . '</Table></Worksheet></Workbook>';
|
||
$path = tempnam(sys_get_temp_dir(), 'alipay-statement-') . '.xls';
|
||
file_put_contents($path, $xml);
|
||
|
||
return $path;
|
||
}
|
||
}
|