bharat_erp/lib/shared/models/purchase_order_model.dart

240 lines
8.5 KiB
Dart

import 'package:freezed_annotation/freezed_annotation.dart';
part 'purchase_order_model.freezed.dart';
part 'purchase_order_model.g.dart';
String _idFromJson(Object? value) => value?.toString() ?? '';
int? _intFromJsonNullable(Object? value) {
if (value == null) return null;
if (value is int) return value;
if (value is num) return value.toInt();
return int.tryParse(value.toString());
}
double? _doubleFromJsonNullable(Object? value) {
if (value == null) return null;
if (value is double) return value;
if (value is num) return value.toDouble();
return double.tryParse(value.toString());
}
DateTime? _dateFromJsonNullable(Object? value) {
if (value == null) return null;
if (value is DateTime) return value;
return DateTime.tryParse(value.toString());
}
Object? _readNestedName(Map<dynamic, dynamic> json, String flatKey, String nestedKey) {
final flat = json[flatKey];
if (flat is String && flat.isNotEmpty) return flat;
final nested = json[nestedKey];
if (nested is Map) {
return nested['name'] ?? nested['vendor_name'];
}
return null;
}
Object? _readVendorName(Map<dynamic, dynamic> json, String key) =>
_readNestedName(json, 'vendor_name', 'vendor');
Object? _readPlantName(Map<dynamic, dynamic> json, String key) =>
_readNestedName(json, 'plant_name', 'plant');
Object? _readWarehouseName(Map<dynamic, dynamic> json, String key) =>
_readNestedName(json, 'warehouse_name', 'warehouse');
Object? _readItemName(Map<dynamic, dynamic> json, String key) {
final flat = json['item_name'];
if (flat is String && flat.isNotEmpty) return flat;
final nested = json['item'];
if (nested is Map) return nested['name'];
return null;
}
Object? _readItemCode(Map<dynamic, dynamic> json, String key) {
final flat = json['item_code'];
if (flat is String && flat.isNotEmpty) return flat;
final nested = json['item'];
if (nested is Map) return nested['code'];
return null;
}
Object? _readUomName(Map<dynamic, dynamic> json, String key) {
final flat = json['uom_name'];
if (flat is String && flat.isNotEmpty) return flat;
final nested = json['uom'];
if (nested is Map) return nested['name'];
return null;
}
Object? _readPoNumber(Map<dynamic, dynamic> json, String key) {
final poNumber = json['po_number'];
if (poNumber != null && poNumber.toString().trim().isNotEmpty) {
return poNumber.toString();
}
final poNo = json['po_no'];
if (poNo != null && poNo.toString().trim().isNotEmpty) {
return poNo.toString();
}
return null;
}
Object? _readGrandTotal(Map<dynamic, dynamic> json, String key) =>
_doubleFromJsonNullable(json['grand_total'] ?? json['total_amount']);
Object? _readTaxTotal(Map<dynamic, dynamic> json, String key) =>
_doubleFromJsonNullable(json['tax_total'] ?? json['tax_amount']);
Object? _readSubTotal(Map<dynamic, dynamic> json, String key) =>
_doubleFromJsonNullable(json['sub_total'] ?? json['taxable_amount']);
@freezed
class PurchaseOrderModel with _$PurchaseOrderModel {
const PurchaseOrderModel._();
const factory PurchaseOrderModel({
@JsonKey(fromJson: _idFromJson) required String id,
@JsonKey(name: 'po_number', readValue: _readPoNumber) String? poNo,
@JsonKey(name: 'po_date', fromJson: _dateFromJsonNullable) DateTime? poDate,
@JsonKey(name: 'po_type') String? poType,
@Default('DRAFT') String status,
@JsonKey(name: 'vendor_id', fromJson: _intFromJsonNullable) int? vendorId,
@JsonKey(name: 'vendor_name', readValue: _readVendorName) String? vendorName,
@JsonKey(name: 'plant_id', fromJson: _intFromJsonNullable) int? plantId,
@JsonKey(name: 'plant_name', readValue: _readPlantName) String? plantName,
@JsonKey(name: 'warehouse_id', fromJson: _intFromJsonNullable) int? warehouseId,
@JsonKey(name: 'warehouse_name', readValue: _readWarehouseName) String? warehouseName,
@JsonKey(name: 'brand_id', fromJson: _intFromJsonNullable) int? brandId,
@JsonKey(name: 'payment_term_id', fromJson: _intFromJsonNullable) int? paymentTermId,
@JsonKey(name: 'delivery_term_id', fromJson: _intFromJsonNullable) int? deliveryTermId,
@JsonKey(name: 'expected_delivery_date', fromJson: _dateFromJsonNullable)
DateTime? expectedDeliveryDate,
@JsonKey(name: 'discount_amount', fromJson: _doubleFromJsonNullable)
double? discountAmount,
@JsonKey(name: 'freight_charges', fromJson: _doubleFromJsonNullable)
double? freightCharges,
@JsonKey(name: 'other_charges', fromJson: _doubleFromJsonNullable)
double? otherCharges,
@JsonKey(name: 'sub_total', readValue: _readSubTotal)
double? taxableAmount,
@JsonKey(name: 'tax_total', readValue: _readTaxTotal)
double? taxAmount,
@JsonKey(name: 'grand_total', readValue: _readGrandTotal)
double? totalAmount,
@JsonKey(name: 'terms_and_conditions') String? termsAndConditions,
String? remarks,
@JsonKey(name: 'revision_no', fromJson: _intFromJsonNullable) int? revisionNo,
@JsonKey(name: 'created_at', fromJson: _dateFromJsonNullable) DateTime? createdAt,
@JsonKey(name: 'updated_at', fromJson: _dateFromJsonNullable) DateTime? updatedAt,
@Default([]) List<PurchaseOrderItemModel> items,
}) = _PurchaseOrderModel;
factory PurchaseOrderModel.fromJson(Map<String, dynamic> json) =>
_$PurchaseOrderModelFromJson(json);
bool get canEdit =>
status.toUpperCase() == 'DRAFT' || status.toUpperCase() == 'REJECTED';
bool get canDelete => canEdit;
bool get canSubmit => status.toUpperCase() == 'DRAFT';
bool get canApprove {
final s = status.toUpperCase();
return s == 'SUBMITTED' || s == 'PENDING_APPROVAL' || s == 'PENDING';
}
bool get canReject => canApprove;
bool get canAmend => status.toUpperCase() == 'APPROVED';
bool get canCancel {
final s = status.toUpperCase();
return s != 'CANCELLED' && s != 'DRAFT';
}
}
@freezed
class PurchaseOrderItemModel with _$PurchaseOrderItemModel {
const factory PurchaseOrderItemModel({
@JsonKey(fromJson: _idFromJson) required String id,
@JsonKey(name: 'po_id', fromJson: _idFromJson) String? poId,
@JsonKey(name: 'item_id', fromJson: _intFromJsonNullable) int? itemId,
@JsonKey(name: 'item_code', readValue: _readItemCode) String? itemCode,
@JsonKey(name: 'item_name', readValue: _readItemName) String? itemName,
@JsonKey(name: 'line_no', fromJson: _intFromJsonNullable) int? lineNo,
@JsonKey(name: 'ordered_qty', fromJson: _doubleFromJsonNullable)
double? orderedQty,
@JsonKey(name: 'received_qty', fromJson: _doubleFromJsonNullable)
double? receivedQty,
@JsonKey(name: 'uom_id', fromJson: _intFromJsonNullable) int? uomId,
@JsonKey(name: 'uom_name', readValue: _readUomName) String? uomName,
@JsonKey(fromJson: _doubleFromJsonNullable) double? rate,
@JsonKey(name: 'discount_pct', fromJson: _doubleFromJsonNullable)
double? discountPct,
@JsonKey(name: 'discount_amount', fromJson: _doubleFromJsonNullable)
double? discountAmount,
@JsonKey(name: 'gst_rate_id', fromJson: _intFromJsonNullable) int? gstRateId,
@JsonKey(name: 'hsn_code_id', fromJson: _intFromJsonNullable) int? hsnCodeId,
@JsonKey(name: 'line_amount', fromJson: _doubleFromJsonNullable)
double? lineAmount,
String? remarks,
}) = _PurchaseOrderItemModel;
factory PurchaseOrderItemModel.fromJson(Map<String, dynamic> json) =>
_$PurchaseOrderItemModelFromJson(json);
}
@freezed
class PurchaseOrderListQuery with _$PurchaseOrderListQuery {
const factory PurchaseOrderListQuery({
@Default(1) int page,
@Default(20) int limit,
String? search,
String? status,
String? poType,
int? vendorId,
int? plantId,
String? dateFrom,
String? dateTo,
}) = _PurchaseOrderListQuery;
}
const poTypeOptions = [
('RAW_MATERIAL', 'Raw Material'),
('PACKING_MATERIAL', 'Packing Material'),
('ASSET_CAPITAL', 'Asset / Capital'),
('SERVICE', 'Service'),
('GENERAL', 'General'),
];
const poStatusOptions = [
('DRAFT', 'Draft'),
('SUBMITTED', 'Submitted'),
('PENDING_APPROVAL', 'Pending Approval'),
('APPROVED', 'Approved'),
('REJECTED', 'Rejected'),
('CANCELLED', 'Cancelled'),
('PARTIALLY_RECEIVED', 'Partially Received'),
('FULLY_RECEIVED', 'Fully Received'),
];
String poTypeLabel(String? value) {
if (value == null) return '';
return poTypeOptions
.where((e) => e.$1 == value)
.map((e) => e.$2)
.firstOrNull ??
value;
}
String poStatusLabel(String? value) {
if (value == null) return '';
return poStatusOptions
.where((e) => e.$1 == value)
.map((e) => e.$2)
.firstOrNull ??
value.replaceAll('_', ' ');
}