user->attachPermission( Permission::where('name', 'read-admin-panel')->firstOrFail() ); } public function test_import_reads_new_optional_columns(): void { $path = $this->makeCsv([ // 「店铺」是「店铺名称」的别名写法(财务系统提供成本5-6.xlsx 用的列名) ['来源', '快递单号', '交易单号', '条形码', '成品配件', '提供成本运费', '店铺'], ['提供成本7月汇总', '79015585514691', '5121853455486000631', 'cbz000203N1221V01', '成品运费', '6.7', '淘宝-亿家达家居鞋柜电脑桌'], ['提供成本7月汇总', '', '5121853455486000632', 'DNZ023905N1221V01', '配件运费', '1.5', ''], ]); try { $result = app(CourierFreightImporter::class)->import($path, $this->company->id, true, 'test'); } finally { @unlink($path); } $this->assertSame(2, $result['inserted']); $row = CourierFreightRow::query()->where('company_id', $this->company->id) ->where('transaction_no', '5121853455486000631')->firstOrFail(); $this->assertSame('提供成本7月汇总', $row->source); $this->assertSame('79015585514691', $row->express_no); $this->assertSame('cbz000203N1221V01', $row->barcode); $this->assertSame('淘宝-亿家达家居鞋柜电脑桌', $row->shop_name); $this->assertSame('成品运费', $row->part); $this->assertSame(6.7, (float) $row->freight_amount); $blank = CourierFreightRow::query()->where('company_id', $this->company->id) ->where('transaction_no', '5121853455486000632')->firstOrFail(); $this->assertNull($blank->express_no); $this->assertNull($blank->shop_name); } public function test_import_old_file_without_optional_columns_still_works(): void { $path = $this->makeCsv([ ['来源', '成品配件', '交易单号', '提供成本运费'], ['8月提供成本', '成品运费', 'X-1', '2.5'], ]); try { $result = app(CourierFreightImporter::class)->import($path, $this->company->id, true, 'test'); } finally { @unlink($path); } $this->assertSame(1, $result['inserted']); $row = CourierFreightRow::query()->where('company_id', $this->company->id)->firstOrFail(); $this->assertNull($row->express_no); $this->assertNull($row->barcode); $this->assertNull($row->shop_name); } public function test_page_shows_new_stored_columns(): void { $path = $this->makeCsv([ ['来源', '快递单号', '交易单号', '条形码', '成品配件', '提供成本运费', '店铺名称'], ['提供成本7月汇总', '79015585514691', 'T-0001', 'cbz000203N1221V01', '成品运费', '6.7', '淘宝-亿家达家居鞋柜电脑桌'], ]); try { app(CourierFreightImporter::class)->import($path, $this->company->id, true, 'test'); } finally { @unlink($path); } $page = $this->loginAs()->get(route('business.pages.show', [ 'section' => 'financial-operations', 'page' => 'courier-freight', ])); $page->assertOk() ->assertSee('快递运费') ->assertSee('快递单号') ->assertSee('条形码') ->assertSee('店铺名称') ->assertSee('T-0001') ->assertSee('79015585514691') ->assertSee('cbz000203N1221V01') ->assertSee('淘宝-亿家达家居鞋柜电脑桌'); } public function test_import_from_xlsx_reads_optional_columns(): void { // xlsx 走 XlsxSheetReader 流式读取,和 csv 分两条代码路径,单独覆盖 $path = $this->makeXlsx([ // 列名用「店铺」别名,与「财务系统提供成本5-6.xlsx」一致 ['来源', '快递单号', '交易单号', '条形码', '成品配件', '提供成本运费', '店铺'], ['提供成本8月汇总', '79015585514648', '3310332098698014581', 'cbz000204N1221V01', '成品运费', '9.4', '新佰广1688'], ]); try { $result = app(CourierFreightImporter::class)->import($path, $this->company->id, true, 'test'); } finally { @unlink($path); } $this->assertSame(1, $result['inserted']); $row = CourierFreightRow::query()->where('company_id', $this->company->id)->firstOrFail(); $this->assertSame('提供成本8月汇总', $row->source); $this->assertSame('79015585514648', $row->express_no); $this->assertSame('cbz000204N1221V01', $row->barcode); $this->assertSame('新佰广1688', $row->shop_name); $this->assertSame(9.4, (float) $row->freight_amount); } /** @param list> $rows */ private function makeCsv(array $rows): string { $path = tempnam(sys_get_temp_dir(), 'courier-') . '.csv'; $handle = fopen($path, 'wb'); fwrite($handle, "\xEF\xBB\xBF"); foreach ($rows as $row) { fputcsv($handle, $row); } fclose($handle); return $path; } /** * 造一个最小 xlsx:字符串走 inlineStr、dimension 只写 A1(与聚水潭导出同形态)。 * * @param list> $rows */ private function makeXlsx(array $rows): string { $path = tempnam(sys_get_temp_dir(), 'courier-') . '.xlsx'; $sheet = '' . '' . ''; foreach ($rows as $rowIndex => $values) { $sheet .= ''; foreach ($values as $columnIndex => $value) { $reference = Coordinate::stringFromColumnIndex($columnIndex + 1) . ($rowIndex + 1); $sheet .= '' . htmlspecialchars((string) $value, ENT_XML1) . ''; } $sheet .= ''; } $sheet .= ''; $zip = new \ZipArchive(); $this->assertTrue($zip->open($path, \ZipArchive::CREATE | \ZipArchive::OVERWRITE) === true); $zip->addFromString('[Content_Types].xml', '' . '' . '' . '' . '' . '' . ''); $zip->addFromString('_rels/.rels', '' . '' . '' . ''); $zip->addFromString('xl/workbook.xml', '' . '' . ''); $zip->addFromString('xl/_rels/workbook.xml.rels', '' . '' . '' . ''); $zip->addFromString('xl/worksheets/sheet1.xml', "\xEF\xBB\xBF" . $sheet); $zip->close(); return $path; } }