Task #35 » FacilityCSVDocumentation.md
Facility CSV Import/Export Documentation
Tổng quan
Tài liệu này mô tả chi tiết về chức năng import/export CSV cho module Facility
THAY ĐỔI QUAN TRỌNG
- Trước đây: CSV có 58 fields
- Hiện tại: CSV đã thay đổi, còn 18 fields
-
Database: Bảng
facilitiesđã được thay đổi -
Field mới: Thêm field
状態(status) để quản lý trạng thái active/inactive
Database Structure
Tables được sử dụng trong Facility CSV Import/Export
Import Process
- facilities - Bảng chính lưu thông tin Facility
- facility_category_relations - Bảng quan hệ giữa Facility và Category
Export Process
- facilities - Bảng chính lấy thông tin Facility
- facility_category_relations - Bảng quan hệ để lấy Category names
- facility_categories - Bảng master để lấy Category names
- owner_accounts - Bảng tham chiếu để lấy Manager name
1. facilities (Bảng chính) - CẬP NHẬT MỚI
| Column Name | Data Type | Length | Nullable | Default | Comment |
|---|---|---|---|---|---|
| id | BIGINT | - | NO | - | Primary Key |
| name | VARCHAR | 64 | NO | - | 施設名 |
| name_kana | VARCHAR | 128 | NO | - | 施設名カナ |
| area | VARCHAR | 32 | NO | - | エリア |
| postal_code | VARCHAR | 8 | NO | - | 郵便番号 |
| prefecture | VARCHAR | 8 | NO | - | 都道府県 |
| city | VARCHAR | 128 | NO | - | 市区郡 |
| ward | VARCHAR | 128 | YES | - | 行政区 |
| address | VARCHAR | 128 | NO | - | 町名番地 |
| building | VARCHAR | 64 | YES | - | 建物 |
| phone | VARCHAR | 16 | NO | - | 施設電話番号 |
| parking | TINYINT | - | NO | - | 駐車場利用(0:-、1:利用可、2:不可) |
| parking_notes | VARCHAR | 1024 | YES | - | 駐車場の備考 |
| manager | VARCHAR | 60 | YES | - | 管理担当者 |
| status | TINYINT | - | NO | 1 | 状態(1:有効、2:無効) |
| created_at | TIMESTAMP | - | NO | - | Created timestamp |
| updated_at | TIMESTAMP | - | NO | - | Updated timestamp |
Indexes:
-
id(PRIMARY KEY)
LƯU Ý: Cấu trúc cũ (58 fields) đã được đơn giản hóa thành 15 fields
2. facility_category_relations (Bảng quan hệ category)
| Column Name | Data Type | Length | Nullable | Default | Comment |
|---|---|---|---|---|---|
| id | BIGINT | - | NO | - | Primary Key |
| facility_id | INT | - | NO | - | 施設ID |
| facility_category_id | INT | - | NO | - | 施設カテゴリID |
| created_at | TIMESTAMP | - | NO | - | Created timestamp |
| updated_at | TIMESTAMP | - | NO | - | Updated timestamp |
Indexes:
-
facility_id(INDEX)
3. facility_categories (Bảng master category - được tạo trong seeder)
| Column Name | Data Type | Length | Nullable | Default | Comment |
|---|---|---|---|---|---|
| id | INT | - | NO | - | Primary Key (Auto Increment) |
| name | VARCHAR | 60 | NO | - | 施設カテゴリ名 |
| status | TINYINT | - | NO | 1 | 状態(1:有効、2:無効) |
| created_at | TIMESTAMP | - | NO | - | Created timestamp |
| updated_at | TIMESTAMP | - | NO | - | Updated timestamp |
4. owner_accounts (Bảng tham chiếu manager)
| Column Name | Data Type | Length | Nullable | Default | Comment |
|---|---|---|---|---|---|
| id | BIGINT | - | NO | - | Primary Key |
| user_id | BIGINT | - | NO | - | 認証ユーザID (UNIQUE) |
| owner_owner_account_id | BIGINT | - | NO | - | オーナー単位のオーナアカウントID |
| owner_organization_id | INT | - | NO | - | オーナー企業ID |
| main_flag | TINYINT | - | NO | 2 | メインフラグ(1:メイン, 2:サブ) |
| branch_name | VARCHAR | 60 | YES | - | 支店名 |
| shop_name | VARCHAR | 60 | YES | - | 店舗名 |
| name | VARCHAR | 60 | NO | - | オーナーアカウント名 |
| department | VARCHAR | 60 | YES | - | 所属 |
| position | VARCHAR | 60 | YES | - | 役職 |
| tel | VARCHAR | 15 | NO | - | 電話番号 |
| is_test | TINYINT | - | NO | 0 | テストフラグ(0:本番, 1:テスト) |
| created_at | TIMESTAMP | - | NO | - | Created timestamp |
| updated_at | TIMESTAMP | - | NO | - | Updated timestamp |
Indexes:
-
user_id(UNIQUE INDEX) -
owner_organization_id(INDEX)
CSV Field Structure
THAY ĐỔI QUAN TRỌNG: Từ 58 fields xuống 15 fields
Format cũ (58 fields) - ĐÃ NGỪNG SỬ DỤNG
施設ID,施設名,施設名カナ,実施場所,独自ID,エリア,郵便番号,都道府県,市区郡,行政区,町名番地,建物,施設電話番号,実施場所の広さ,催事開始時間,催事終了時間,屋内外(0:要確認、1:屋内、2:屋外(屋根あり)、3:屋外(屋根なし)),屋内外コメント,平日料金,土曜料金,日祝料金,電源の有無(0:-、1:有、2:無),電源のコメント,デスクの有無(0:-、1:有、2:無),デスクのコメント,椅子の有無(0:-、1:有、2:無),椅子のコメント,Wi-Fiの有無(0:-、1:有、2:無),Wi-Fiのコメント,飲食の有無(0:-、1:有、2:無),飲食のコメント,NG商材の有無(0:未設定,1:有, 2:無),NG商材のコメント,コメント,注意コメント,開催不可曜日,申請期日,回答目安,回答予定日数,申請時の注意事項,開催時の注意事項,事前打ち合わせ,備品貸出,備品に関する備考,台車貸出,駐車場利用(0:-、1:利用可、2:不可),駐車場の備考,当日搬入開始可能時間,完全撤退時間,キャンセルポリシー,社内メモ,空き状況通知(1:通知する,2:通知しない),空き状況通知対象週(週間後~),空き状況通知対象週(~週間後),管理担当者,カテゴリー1,カテゴリー2,カテゴリー3
Format mới (15 fields) - HIỆN TẠI
| STT | Field Name (Japanese) | Field Name (English) | Data Type | Required | Max Length | Validation Rules | Database Column | Description |
|---|---|---|---|---|---|---|---|---|
| 1 | 施設ID | Facility ID | Integer | No | - | 1-999999 | id | ID của facility (để trống nếu tạo mới) |
| 2 | 施設名 | Facility Name | Text | Yes | 64 | 2-64 chars | name | Tên Facility |
| 3 | 施設名カナ | Facility Name Kana | Text | Yes | 128 | 2-128 chars | name_kana | Tên Facility bằng katakana |
| 4 | エリア | Area | Text | Yes | 32 | Must exist in Area list | area | Khu vực |
| 5 | 郵便番号 | Postal Code | Text | Yes | 8 | Format: xxx-xxxx | postal_code | Mã bưu điện |
| 6 | 都道府県 | Prefecture | Text | Yes | 8 | Must match Area | prefecture | Tỉnh/thành phố |
| 7 | 市区郡 | City | Text | Yes | 128 | - | city | Quận/huyện |
| 8 | 行政区 | Ward | Text | No | 128 | - | ward | Phường/xã |
| 9 | 町名番地 | Address | Text | Yes | 128 | - | address | Địa chỉ chi tiết |
| 10 | 建物 | Building | Text | No | 64 | - | building | Tòa nhà |
| 11 | 施設電話番号 | Facility Phone | Text | Yes | 16 | Phone format | phone | Số điện thoại Facility |
| 12 | 駐車場利用 | Parking Usage | Integer | Yes | - | 0-2 | parking | 0: -、1: 利用可、2: 不可 |
| 13 | 駐車場の備考 | Parking Notes | Text | No | 1024 | - | parking_notes | Ghi chú về bãi đỗ xe |
| 14 | 管理担当者 | Manager | Text | Yes | 60 | Must exist in Owner Account | manager | Người quản lý |
| 15 | カテゴリー1 | Category 1 | Text | Yes | 60 | Must exist in Facility Category | facility_category_relations | Danh mục 1 |
| 16 | カテゴリー2 | Category 2 | Text | No | 60 | Must exist in Facility Category | facility_category_relations | Danh mục 2 |
| 17 | カテゴリー3 | Category 3 | Text | No | 60 | Must exist in Facility Category | facility_category_relations | Danh mục 3 |
| 18 | 状態 | Status | Integer | Yes | - | 1-2 | status | 1: 有効、2: 無効 (Field mới) |
CSV Format Examples
CSV Header Structure
Format cũ (58 fields) - ĐÃ NGỪNG SỬ DỤNG
施設ID,施設名,施設名カナ,実施場所,独自ID,エリア,郵便番号,都道府県,市区郡,行政区,町名番地,建物,施設電話番号,実施場所の広さ,催事開始時間,催事終了時間,屋内外(0:要確認、1:屋内、2:屋外(屋根あり)、3:屋外(屋根なし)),屋内外コメント,平日料金,土曜料金,日祝料金,電源の有無(0:-、1:有、2:無),電源のコメント,デスクの有無(0:-、1:有、2:無),デスクのコメント,椅子の有無(0:-、1:有、2:無),椅子のコメント,Wi-Fiの有無(0:-、1:有、2:無),Wi-Fiのコメント,飲食の有無(0:-、1:有、2:無),飲食のコメント,NG商材の有無(0:未設定,1:有, 2:無),NG商材のコメント,コメント,注意コメント,開催不可曜日,申請期日,回答目安,回答予定日数,申請時の注意事項,開催時の注意事項,事前打ち合わせ,備品貸出,備品に関する備考,台車貸出,駐車場利用(0:-、1:利用可、2:不可),駐車場の備考,当日搬入開始可能時間,完全撤退時間,キャンセルポリシー,社内メモ,空き状況通知(1:通知する,2:通知しない),空き状況通知対象週(週間後~),空き状況通知対象週(~週間後),管理担当者,カテゴリー1,カテゴリー2,カテゴリー3
Format mới (18 fields) - HIỆN TẠI
施設ID,施設名,施設名カナ,エリア,郵便番号,都道府県,市区郡,行政区,町名番地,建物,施設電話番号,駐車場利用(0:-、1:利用可、2:不可),駐車場の備考,管理担当者,カテゴリー1,カテゴリー2,カテゴリー3,状態(1:有効、2:無効)
Import CSV Sample Data (Format mới)
,東京コンベンションセンター,トウキョウコンベンションセンター,関東,123-4567,東京都,渋谷区,神南,1-1-1,ビルA,03-1234-5678,1,駐車場利用可,田中太郎,会議室,大型会議室,,1
File Processing
Import File Processing
1. File Upload & Storage
// File được upload và lưu tạm thời
$filePath = storage_path('app/tmp/' . $fileName);
$file->move($filePath);
// File được xử lý theo chunk (100 records/chunk)
$chunkSize = 100;
2. File Validation
// Kiểm tra file type (.csv)
if ($file->getClientOriginalExtension() !== 'csv') {
throw new RuntimeException('CSVファイルのみアップロード可能です。');
}
// Kiểm tra số lượng records
if (!ImportCsvUtility::checkRecordSize($file)) {
throw new RuntimeException('データ数が3000件を超えています。');
}
// Kiểm tra header
ImportCsvUtility::checkCsvHeader($file, $this->createHeader(), '施設');
3. Encoding Processing
// Chuyển đổi encoding
public static function convertStringCode($value)
{
$strType = mb_detect_encoding($value, ['UTF-8', 'SJIS-win']);
if ($strType == 'SJIS-win') {
$value = mb_convert_encoding($value, 'UTF-8', 'SJIS-win');
}
return $value;
}
// Xử lý BOM
$wk = preg_replace("/^\xEF\xBB\xBF/", '', $wk);
4. Error File Generation
// Tạo error file với BOM
$fileName = 'Facility_import_error_' . date('Ymd') . '.csv';
$filePath = $dir . '/' . $fileName;
$file = fopen($filePath, 'w');
// Thêm BOM
fwrite($file, "\xEF\xBB\xBF");
// Write header
fputcsv($file, $this->createHeader());
Export File Processing
1. Data Retrieval
// Lấy dữ liệu từ database
$facilities = $this->facilitySelectRepository->select($filterDto);
// Chunk processing để tránh memory overflow
$chunks = $facilities->chunk(config('web.db.chunkSize'));
2. File Generation
// Tạo CSV file
$file = CsvUtility::createCsvFile($filePath);
// Write header
fputcsv($file, $this->createHeader());
// Write data theo chunk
foreach ($chunks as $chunk) {
foreach ($chunk as $facility) {
fputcsv($file, $this->formatData($facility));
}
}
3. File Storage & Download
// File được lưu trong storage/app/tmp/
$fileName = 'Facility_' . date('YmdHis') . '.csv';
$filePath = storage_path('app/tmp/' . $fileName);
// Download link
return response()->download($filePath, $fileName);
Database Operations
Import Database Operations
1. Facility Table Operations
// Insert new facility
if (empty($wk->ownerFacilityId)) {
$facility = $this->facilityUpsertRepository->insert($wk);
} else {
// Update existing facility
$facility = $this->facilityUpsertRepository->update($wk);
}
2. Category Relations Operations
// Delete existing categories
$this->facilityCategoryRelationUpsertRepository->deleteByFacilityId($facility->facilityId);
// Insert new categories
$this->saveCategory($facility->facilityId, $wk->category1);
$this->saveCategory($facility->facilityId, $wk->category2);
$this->saveCategory($facility->facilityId, $wk->category3);
3. Transaction Handling
DB::transaction(function () use ($insertRecords) {
foreach ($insertRecords as $wk) {
// Facility operations
$facility = $this->facilityUpsertRepository->insert($wk);
// Category operations
$this->facilityCategoryRelationUpsertRepository->deleteByFacilityId($facility->facilityId);
$this->saveCategory($facility->facilityId, $wk->category1);
$this->saveCategory($facility->facilityId, $wk->category2);
$this->saveCategory($facility->facilityId, $wk->category3);
}
});
Export Database Operations
1. Data Retrieval
// Query facilities với filter
$facilities = $this->facilitySelectRepository->select($filterDto);
// Join với categories
$facilities = $facilities->map(function ($facility) {
$facility->facilityCategories = $this->getCategoryNames($facility->facilityId);
return $facility;
});
2. Data Formatting
protected function formatData($dbRecord)
{
$categoryNames = explode(',', $dbRecord->facilityCategories);
return [
$dbRecord->ownerFacilityId,
$dbRecord->name,
$dbRecord->nameKana,
$dbRecord->place,
// ... 58 fields total
$categoryNames[0] ?? '',
$categoryNames[1] ?? '',
$categoryNames[2] ?? ''
];
}
Validation Rules
Business Logic Validation
1. Duplicate Check
- Facility Name: Không được trùng lặp trong cùng organization
- Error: "施設名は既に登録されています。"
2. Area & Prefecture Validation
- Area: Phải tồn tại trong danh sách Area
- Prefecture: Phải khớp với Area đã chọn
- Error: "存在しないエリア名です。" / "エリアに対応しない都道府県名です。"
3. Category Validation
- Category 1: Bắt buộc, phải tồn tại trong Facility Category
- Category 2, 3: Tùy chọn, nếu có thì phải tồn tại
- Error: "カテゴリー1は存在しないカテゴリ名です。"
4. Manager Validation
- Manager: Phải tồn tại trong Owner Account
- Error: "存在しないオーナーアカウントです。"
5. Status Validation
- Status: Phải là 1 (有効) hoặc 2 (無効)
- Error: "状態は1または2で入力してください。"
Import Process
Step 1: File Validation
// Kiểm tra số lượng records
if (!ImportCsvUtility::checkRecordSize($file)) {
throw new RuntimeException('データ数が3000件を超えています。');
}
// Kiểm tra header
ImportCsvUtility::checkCsvHeader($file, $this->createHeader(), '施設');
Step 2: Data Processing
// Chuyển đổi encoding
$csvRecord[] = self::convertStringCode($wk);
// Xử lý BOM
$wk = preg_replace("/^\xEF\xBB\xBF/", '', $wk);
Step 3: Record Validation
// Validate từng field
$validator->validateText('施設名', $obj->name, true, 2, 60);
$validator->validateZip('郵便番号', $obj->zipCode, true);
$validator->validateDigit('平日料金', $obj->weekdaySellPrice, false, 0, 99999999);
// Business logic validation
if (!$this->validateNameAndPlace($obj->ownerFacilityId, $obj->name, $obj->place, $ownerOrganizationId)) {
$validator->addErrorMessage('施設名・実施場所は既に登録されています。');
}
Step 4: Database Operations
// Insert/Update facility
if (empty($wk->ownerFacilityId)) {
$facility = $this->facilityUpsertRepository->insert($wk);
} else {
$facility = $this->facilityUpsertRepository->update($wk);
}
// Update categories
$this->facilityCategoryRelationUpsertRepository->deleteByFacilityId($facility->facilityId);
$this->saveCategory($facility->facilityId, $wk->category1);
$this->saveCategory($facility->facilityId, $wk->category2);
$this->saveCategory($facility->facilityId, $wk->category3);
Export Process
Step 1: Data Retrieval
// Lấy danh sách facilities
$facilities = $this->facilitySelectRepository->select($filterDto);
// Chunk processing
$chunks = $facilities->chunk(config('web.db.chunkSize'));
Step 2: Data Formatting
// Format data cho CSV
return [
$dbRecord->ownerFacilityId,
$dbRecord->name,
$dbRecord->nameKana,
$dbRecord->place,
// ... các field khác
];
Step 3: File Generation
// Tạo CSV file
$file = CsvUtility::createCsvFile($filePath);
fputcsv($file, $this->createHeader());
// Write data
foreach ($chunks as $chunk) {
foreach ($chunk as $facility) {
fputcsv($file, $this->formatData($facility));
}
}
Error Handling
Error File Structure
施設ID,施設名,施設名カナ,実施場所,...,Error
,東京コンベンションセンター,トウキョウコンベンションセンター,メインホールA,...,施設名・実施場所は既に登録されています。
Common Error Messages
File Validation
項目数が正しくありません。最新の施設CSVをダウンロードして項目数を確認してください。
項目名が正しくありません。最新の施設CSVをダウンロードして項目名を確認してください。
データ数が3000件を超えています。
Field Validation
施設名は入力必須です。
施設名は2文字以上で入力してください。
施設名は64文字以内で入力してください。
郵便番号はxxx-xxxxの形式で入力してください。
駐車場利用は0、1、2のいずれかで入力してください。
状態は1または2で入力してください。
Business Logic
施設名は既に登録されています。
存在しないエリア名です。
エリアに対応しない都道府県名です。
存在しないオーナーアカウントです。
カテゴリー1は存在しないカテゴリ名です。
Configuration
CSV Import/Export Config
Environment Variables
# CSV Import Limit
CSV_IMPORT_LIMIT=3000
# Database Chunk Size
DB_CHUNK_SIZE=10000
# Storage Path
SYSTEM_STORAGE_TEMPORARY_PATH=tmp/
# File Expiration (hours)
CSV_DOWNLOAD_FILE_EXPIRED_AT=72
CSV_ERROR_FILE_EXPIRED_AT=336
Config Structure (config/web.php)
'csv' => [
'importLimit' => env('CSV_IMPORT_LIMIT', '3000'), // Max records per import
'downloadFileExpiredAt' => env('CSV_DOWNLOAD_FILE_EXPIRED_AT', 72), // Download file expiration (hours)
'errorFileExpiredAt' => env('CSV_ERROR_FILE_EXPIRED_AT', 336) // Error file expiration (hours)
],
'db' => [
'chunkSize' => env('DB_CHUNK_SIZE', '10000') // Database chunk size for processing
],
Area Mapping
// Supported Areas
$areas = [
'北海道',
'東北',
'関東',
'中部',
'関西',
'中国',
'四国',
'九州',
'沖縄'
];
Category Mapping
// Facility Categories
$categories = [
'会議室',
'展示場',
'ホール',
'スタジオ',
'オフィス',
// ... more categories
];
Performance Considerations
Chunk Processing
- Chunk size: 100 records per chunk
- Memory usage: Giảm memory usage bằng cách xử lý từng chunk
- Error handling: Mỗi chunk được xử lý độc lập
Database Operations
- Batch insert: Sử dụng chunk để insert/update
- Transaction: Mỗi chunk được wrap trong transaction
- Error rollback: Rollback toàn bộ chunk nếu có lỗi
Security Considerations
File Upload Security
- File type validation: Chỉ chấp nhận .csv
- File size limit: Giới hạn số lượng records
- Path traversal protection: Validate file path
Data Validation
- Input sanitization: Tự động chuyển đổi encoding
- SQL injection protection: Sử dụng prepared statements
- XSS protection: Validate và escape output
Access Control
- Authentication: Yêu cầu đăng nhập
- Authorization: Kiểm tra quyền truy cập
- Organization isolation: Chỉ xử lý dữ liệu của organization hiện tại
Troubleshooting
Common Issues
1. Encoding Issues
Problem: Japanese characters display incorrectly
Solution:
- Đảm bảo file CSV có BOM (Byte Order Mark)
- Sử dụng UTF-8 encoding
- Kiểm tra
convertStringCode()function
2. Header Mismatch
Problem: "項目名が正しくありません" error
Solution:
- Download template CSV mới nhất
- Đảm bảo header khớp chính xác
- Kiểm tra thứ tự cột
3. Duplicate Facility
Problem: "施設名・実施場所は既に登録されています" error
Solution:
- Kiểm tra tên Facility và place
- Sử dụng Facility ID để update thay vì tạo mới
- Xóa Facility cũ trước khi tạo mới
4. Category Not Found
Problem: "カテゴリー1は存在しないカテゴリ名です" error
Solution:
- Kiểm tra danh sách category hợp lệ
- Đảm bảo category name khớp chính xác
- Sử dụng category từ template
Debug Information
// Enable debug logging
Log::debug('Facility CSV Import Debug', [
'file_size' => $file->getSize(),
'record_count' => $recordCount,
'validation_errors' => $errors,
'organization_id' => $ownerOrganizationId
]);
Current System Implementation
File Processing
-
Chunk size: 100 records per chunk (configurable via
config('web.db.chunkSize')) - Memory management: Xử lý từng chunk để tránh memory overflow
-
File storage: Temporary files lưu trong
storage/app/tmp/ - File cleanup: Tự động xóa file tạm sau khi xử lý
Error Handling
- Error file generation: Tạo file CSV với BOM chứa records có lỗi
- Error file format: Bao gồm header + data + error message column
-
Error file storage: Lưu trong
storage/app/tmp/với prefixFacility_import_error_ - Error file expiration: Tự động xóa sau 336 giờ (14 ngày)
Validation
- File validation: Kiểm tra extension .csv, số lượng records (max 3000)
- Header validation: Kiểm tra số lượng và tên cột chính xác
- Encoding validation: Tự động chuyển đổi từ SJIS-win sang UTF-8
- Business validation: Kiểm tra duplicate, reference data, business rules
Sequence Diagram
Facility CSV Import Process
sequenceDiagram
participant User as User
participant Frontend as Frontend
participant Controller as Facility Controller
participant Service as Facility CSV Service
participant Utility as ImportCsvUtility
participant Validator as CsvValidate
participant Repository as Facility Repository
participant DB as Database
participant Storage as Storage
participant Mail as Mail Service
User->>Frontend: Upload CSV file
Frontend->>Controller: POST /api/v1/facility/import
Note over Controller: Validate request parameters
Controller->>Service: importCsvFile()
Note over Service: Step 1: File Validation
Service->>Utility: checkRecordSize()
Utility-->>Service: Record count OK/Error
alt Record count exceeds limit
Service-->>Controller: RuntimeException
Controller-->>Frontend: 400 Error
Frontend-->>User: Error message
end
Note over Service: Step 2: Header Validation
Service->>Utility: checkCsvHeader()
Utility->>Utility: readHeader()
Utility-->>Service: Header validation result
alt Header validation fails
Service-->>Controller: RuntimeException
Controller-->>Frontend: 400 Error
Frontend-->>User: Error message
end
Note over Service: Step 3: Create Error File
Service->>Utility: createErrorFile('Facility')
Utility-->>Service: Error file handle
Note over Service: Step 4: Process Records
loop For each record chunk (100 records)
Service->>Utility: readRecords()
Utility-->>Service: CSV records
loop For each record
Service->>Service: createRecordObject()
Service->>Validator: validateRecord()
Note over Validator: Validate each field
Validator->>Validator: validateText('施設名')
Validator->>Validator: validateZip('郵便番号')
Validator->>Validator: validateDigit('平日料金')
Validator->>Validator: validateTime('催事開始時間')
Note over Validator: Business logic validation
Validator->>Service: validateNameAndPlace()
Validator->>Service: validateArea()
Validator->>Service: validatePrefecture()
Validator->>Service: validateFacilityCategory()
Validator->>Service: validateOwnerAccount()
alt Validation fails
Service->>Utility: Write error record
Utility-->>Service: Error file updated
else Validation passes
Service->>Repository: upsertCsvData()
Repository->>DB: Insert/Update facilities
Repository->>DB: Delete facility_category_relations
Repository->>DB: Insert facility_category_relations
DB-->>Repository: Success
Repository-->>Service: Success
end
end
end
Note over Service: Step 5: Final Processing
alt All records valid
Service->>Mail: sendEmail()
Service->>Storage: deleteCsvFile()
Service-->>Controller: Success
Controller-->>Frontend: 200 Success
Frontend-->>User: Success message
else Some records invalid
Service->>Storage: Keep error file
Service-->>Controller: Success with error file
Controller-->>Frontend: 200 Success + error file
Frontend-->>User: Success + error file download
end
Facility CSV Export Process
sequenceDiagram
participant User as User
participant Frontend as Frontend
participant Controller as Facility Controller
participant Service as Facility CSV Service
participant Repository as Facility Repository
participant DB as Database
participant Storage as Storage
User->>Frontend: Click Export CSV
Frontend->>Controller: GET /api/v1/facility/export
Note over Controller: Validate request parameters
Controller->>Service: createCsv()
Note over Service: Step 1: Data Retrieval
Service->>Repository: select(filterDto)
Repository->>DB: SELECT facilities
DB-->>Repository: Facilities data
Repository-->>Service: Facilities collection
Note over Service: Step 2: Create CSV File
Service->>Storage: createCsvFile(filePath)
Storage-->>Service: File handle
Note over Service: Step 3: Write Header
Service->>Service: createHeader()
Service->>Storage: fputcsv(header)
Note over Service: Step 4: Write Data
loop For each facility chunk
Service->>Service: formatData(facility)
Service->>Storage: fputcsv(data)
end
Service->>Storage: fclose(file)
Note over Service: Step 5: Return Download
Service-->>Controller: File path
Controller-->>Frontend: Download response
Frontend-->>User: File download
Cách xem Sequence Diagram:
- Copy code ở trên vào https://mermaid.live/