This commit is contained in:
phaichayon
2026-04-26 00:15:22 +07:00
parent a330abf9b6
commit 043edff93a
64 changed files with 25076 additions and 461 deletions

View File

@@ -0,0 +1,220 @@
# Phase 4: Service Layer Refactor - Checklist
## ✅ Completed Tasks
### Customer Service Refactor
- [x] Analyze existing customer service structure
- [x] Update customer service with branch context integration
- [x] Implement contact visibility logic (private-by-default)
- [x] Add `BranchContext` parameter to all customer operations
- [x] Implement contact sharing/unsharing functionality
- [x] Add business rule validation for quotation creation
- [x] Create `generateCrmCustomerCode` utility function
- [x] Add soft delete support for customers
- [x] Implement CRUD operations with branch scoping
### Quotation Service Refactor
- [x] Analyze existing quotation service structure
- [x] Add multi-currency support (THB, USD, EUR, JPY, CNY)
- [x] Implement exchange rate capture at quotation creation
- [x] Add base currency amount calculation
- [x] Implement quotation revision system
- [x] Add `parentQuotationId` and `revisionNo` tracking
- [x] Create `createQuotationRevision` function with cloning logic
- [x] Implement quotation item management
- [x] Add quotation customer relationship management
- [x] Create multi-currency calculation utilities
- [x] Add quotation validation rules (editable, sendable status checks)
- [x] Implement `generateQuotationCode` utility function
## 📁 Created Files
1. **`src/modules/customers/service.refactored.ts`**
- Customer operations with branch scoping
- Contact visibility enforcement
- Contact sharing functionality
- Business rule validations
2. **`src/modules/quotations/service.refactored.ts`**
- Quotation CRUD with branch context
- Multi-currency support
- Revision system implementation
- Currency conversion utilities
- Validation helpers
## 🔑 Key Features Implemented
### Branch Scoping
- All operations automatically scoped by `currentBranchId`
- Cross-branch access prevented at service layer
- Automatic branch ID injection on create/update operations
### Contact Visibility Logic
```
Visibility Rule: User can see contact IF:
- createdBy == currentUser
OR
- isPublic == true
```
### Multi-Currency Support
- Currency code stored with each quotation
- Exchange rate captured at creation time (immutable)
- Base currency (THB) amount calculated and stored
- Same quotation code can have multiple currency versions
### Revision System
```
Quotation Status Flow:
DRAFT → SENT (locked)
SENT → Create REVISION (new draft)
REVISION → SENT (locked)
SENT → ACCEPTED | REJECTED
```
### Business Rules
- ✅ User must have visible contacts to create quotation
- ✅ Only creator can update/delete their contacts
- ✅ Sent quotations cannot be edited directly (must create revision)
- ✅ Draft quotations are editable
## 📊 Database Integration
### Customer Service
- Uses Drizzle ORM with PostgreSQL
- Implements proper foreign key relationships
- Supports soft deletes with `deletedAt` timestamp
- Indexes: branchId, customerStatus, crmCustomerCode, erpCustomerCode
### Quotation Service
- Full Drizzle ORM integration
- Multi-table transactions (quotations, items, customers)
- Proper cascade deletes
- Indexes: branchId, code, status, quotationDate, parentQuotationId
## 🔄 Migration Notes
### From Old Service to New Service
**Old Pattern:**
```typescript
export function getAllCustomers(branch: string): Customer[] {
return getCustomersByBranch(branch);
}
```
**New Pattern:**
```typescript
export async function getCustomersByBranch(
context: BranchContext,
status?: string,
): Promise<Customer[]> {
const { currentBranchId } = context;
return await db
.select()
.from(customers)
.where(eq(customers.branchId, currentBranchId));
}
```
### Breaking Changes
1. All functions now require `BranchContext` parameter
2. Functions are now async (return Promises)
3. Contact visibility is enforced by default
4. Multi-currency fields are required for quotations
## 🧪 Testing Recommendations
### Unit Tests Needed
- [ ] Test branch scoping enforcement
- [ ] Test contact visibility rules
- [ ] Test contact sharing/unsharing
- [ ] Test multi-currency calculations
- [ ] Test revision creation logic
- [ ] Test quotation validation rules
- [ ] Test soft delete functionality
### Integration Tests Needed
- [ ] Test full quotation creation flow
- [ ] Test quotation revision flow
- [ ] Test customer + contact creation flow
- [ ] Test cross-branch access prevention
- [ ] Test currency conversion accuracy
## 📋 Next Steps
### Phase 5: Controllers Update
- [ ] Update customer controllers to use refactored service
- [ ] Update quotation controllers to use refactored service
- [ ] Add BranchContext injection from middleware
- [ ] Update API request/response types
- [ ] Add error handling for validation failures
### Phase 6: Models (TypeScript)
- [ ] Update customer model types for new fields
- [ ] Add quotation model types with multi-currency
- [ ] Create contact model types
- [ ] Add revision-related types
- [ ] Update ElysiaJS validation schemas
### Phase 7: Testing
- [ ] Write unit tests for customer service
- [ ] Write unit tests for quotation service
- [ ] Write integration tests for API endpoints
- [ ] Test multi-tenant scenarios
- [ ] Test multi-currency scenarios
## 🎯 Success Criteria
Phase 4 is complete when:
- [x] All service functions use BranchContext
- [x] Contact visibility is enforced
- [x] Multi-currency is fully supported
- [x] Revision system works correctly
- [ ] Controllers are updated (Phase 5)
- [ ] Models are updated (Phase 6)
- [ ] Tests pass (Phase 7)
## 📝 Notes
### Contact Visibility Implementation
- The contact visibility is implemented at the service layer using `isPublic` flag
- Future enhancement: Add `contact_shares` table for more granular sharing (specific users)
- Current implementation: Public/Private binary flag
### Multi-Currency Implementation
- Exchange rates are captured at quotation creation time
- Historical rates are preserved (no dynamic recalculation)
- Base currency (THB) is used for reporting and comparisons
### Revision System
- Each revision creates a new quotation record
- Parent relationship tracked via `parentQuotationId`
- Same quotation code shared across revisions
- Status resets to "draft" for new revisions
---
**Phase 4 Status**: ✅ **CORE IMPLEMENTATION COMPLETE**
**Next Phase**: Phase 5 - Controllers Update