part of '../product_dtos.dart'; @freezed class ListProductDto with _$ListProductDto { const ListProductDto._(); const factory ListProductDto({ @JsonKey(name: "products") required List products, @JsonKey(name: "total_count") required int totalCount, @JsonKey(name: "page") required int page, @JsonKey(name: "limit") required int limit, @JsonKey(name: "total_pages") required int totalPages, }) = _ListProductDto; factory ListProductDto.fromJson(Map json) => _$ListProductDtoFromJson(json); ListProduct toDomain() => ListProduct( products: products.map((dto) => dto.toDomain()).toList(), totalCount: totalCount, page: page, limit: limit, totalPages: totalPages, ); } /// Satuan yang menempel pada produk. /// /// Backend hanya dijamin mengirim `unit_id`; sebagian response ikut menyertakan /// objek `unit` lengkap. Kalau ada, dipakai langsung supaya POS tidak perlu /// menunggu master satuan termuat. @freezed class ProductUnitDto with _$ProductUnitDto { const ProductUnitDto._(); const factory ProductUnitDto({ @JsonKey(name: "id") String? id, @JsonKey(name: "name") String? name, @JsonKey(name: "abbreviation") String? abbreviation, }) = _ProductUnitDto; factory ProductUnitDto.fromJson(Map json) => _$ProductUnitDtoFromJson(json); } @freezed class ProductDto with _$ProductDto { const ProductDto._(); const factory ProductDto({ @JsonKey(name: "id") String? id, @JsonKey(name: "organization_id") String? organizationId, @JsonKey(name: "category_id") String? categoryId, @JsonKey(name: "sku") String? sku, @JsonKey(name: "name") String? name, @JsonKey(name: "description") String? description, @JsonKey(name: "price") double? price, @JsonKey(name: "cost") double? cost, @JsonKey(name: "business_type") String? businessType, @JsonKey(name: "image_url") String? imageUrl, @JsonKey(name: "printer_type") String? printerType, @JsonKey(name: "print_to_checker") bool? printToChecker, @JsonKey(name: "metadata") Map? metadata, @JsonKey(name: "is_active") bool? isActive, @JsonKey(name: "created_at") String? createdAt, @JsonKey(name: "updated_at") String? updatedAt, @JsonKey(name: "variants") List? variants, @JsonKey(name: "sell_by") String? sellBy, @JsonKey(name: "unit_id") String? unitId, @JsonKey(name: "unit_name") String? unitName, @JsonKey(name: "unit_abbreviation") String? unitAbbreviation, @JsonKey(name: "unit") ProductUnitDto? unit, }) = _ProductDto; factory ProductDto.fromJson(Map json) => _$ProductDtoFromJson(json); String get _resolvedUnitId => (unitId?.isNotEmpty == true ? unitId : unit?.id) ?? ''; String get _resolvedUnitName => (unitName?.isNotEmpty == true ? unitName : unit?.name) ?? ''; String get _resolvedUnitAbbreviation => (unitAbbreviation?.isNotEmpty == true ? unitAbbreviation : unit?.abbreviation) ?? ''; /// Mapping ke domain Product toDomain() => Product( id: id ?? '', organizationId: organizationId ?? '', categoryId: categoryId ?? '', sku: sku ?? '', name: name ?? '', description: description ?? '', price: price ?? 0.0, cost: cost ?? 0.0, businessType: businessType ?? '', imageUrl: imageUrl ?? '', printerType: printerType ?? '', printToChecker: printToChecker ?? false, metadata: metadata ?? {}, isActive: isActive ?? false, createdAt: createdAt ?? '', updatedAt: updatedAt ?? '', variants: variants?.map((v) => v.toDomain()).toList() ?? [], sellBy: SellBy.normalize(sellBy), unitId: _resolvedUnitId, unitName: _resolvedUnitName, unitAbbreviation: _resolvedUnitAbbreviation, ); Map toMap() => { 'id': id, 'organization_id': organizationId, 'category_id': categoryId, 'sku': sku, 'name': name, 'description': description, 'price': price, 'cost': cost, 'business_type': businessType, 'image_url': imageUrl, 'printer_type': printerType, 'print_to_checker': printToChecker == true ? 1 : 0, 'metadata': metadata != null ? jsonEncode(metadata) : null, 'is_active': isActive == true ? 1 : 0, 'created_at': createdAt, 'updated_at': updatedAt, 'sell_by': SellBy.normalize(sellBy), 'unit_id': _resolvedUnitId, 'unit_name': _resolvedUnitName, 'unit_abbreviation': _resolvedUnitAbbreviation, }; factory ProductDto.fromMap( Map map, List variants, ) => ProductDto( id: map['id'] as String?, organizationId: map['organization_id'] as String?, categoryId: map['category_id'] as String?, sku: map['sku'] as String?, name: map['name'] as String?, description: map['description'] as String?, price: map['price'] != null ? (map['price'] as num).toDouble() : null, cost: map['cost'] != null ? (map['cost'] as num).toDouble() : null, businessType: map['business_type'] as String?, imageUrl: map['image_url'] as String?, printerType: map['printer_type'] as String?, printToChecker: map['print_to_checker'] != null ? (map['print_to_checker'] as int) == 1 : null, metadata: map['metadata'] != null ? jsonDecode(map['metadata'] as String) as Map : null, isActive: map['is_active'] != null ? (map['is_active'] as int) == 1 : null, createdAt: map['created_at'] as String?, updatedAt: map['updated_at'] as String?, variants: variants, sellBy: map['sell_by'] as String?, unitId: map['unit_id'] as String?, unitName: map['unit_name'] as String?, unitAbbreviation: map['unit_abbreviation'] as String?, ); factory ProductDto.fromDomain(Product product) => ProductDto( id: product.id, organizationId: product.organizationId, categoryId: product.categoryId, sku: product.sku, name: product.name, description: product.description, price: product.price, cost: product.cost, businessType: product.businessType, imageUrl: product.imageUrl, printerType: product.printerType, printToChecker: product.printToChecker, metadata: product.metadata, isActive: product.isActive, createdAt: product.createdAt, updatedAt: product.updatedAt, variants: product.variants .map((v) => ProductVariantDto.fromDomain(v)) .toList(), sellBy: product.sellBy, unitId: product.unitId, unitName: product.unitName, unitAbbreviation: product.unitAbbreviation, ); } @freezed class ProductVariantDto with _$ProductVariantDto { const ProductVariantDto._(); const factory ProductVariantDto({ @JsonKey(name: "id") String? id, @JsonKey(name: "product_id") String? productId, @JsonKey(name: "name") String? name, @JsonKey(name: "price_modifier") double? priceModifier, @JsonKey(name: "cost") double? cost, @JsonKey(name: "metadata") Map? metadata, @JsonKey(name: "created_at") String? createdAt, @JsonKey(name: "updated_at") String? updatedAt, }) = _ProductVariantDto; factory ProductVariantDto.fromJson(Map json) => _$ProductVariantDtoFromJson(json); /// Mapping ke domain ProductVariant toDomain() => ProductVariant( id: id ?? '', productId: productId ?? '', name: name ?? '', priceModifier: priceModifier ?? 0.0, cost: cost ?? 0.0, metadata: metadata ?? {}, createdAt: createdAt ?? '', updatedAt: updatedAt ?? '', ); Map toMap() => { 'id': id, 'product_id': productId, 'name': name, 'price_modifier': priceModifier, 'cost': cost, 'metadata': metadata != null ? jsonEncode(metadata) : null, 'created_at': createdAt, 'updated_at': updatedAt, }; factory ProductVariantDto.fromMap(Map map) => ProductVariantDto( id: map['id'] as String?, productId: map['product_id'] as String?, name: map['name'] as String?, priceModifier: map['price_modifier'] != null ? (map['price_modifier'] as num).toDouble() : null, cost: map['cost'] != null ? (map['cost'] as num).toDouble() : null, metadata: map['metadata'] != null ? jsonDecode(map['metadata'] as String) as Map : null, createdAt: map['created_at'] as String?, updatedAt: map['updated_at'] as String?, ); factory ProductVariantDto.fromDomain(ProductVariant variant) => ProductVariantDto( id: variant.id, productId: variant.productId, name: variant.name, priceModifier: variant.priceModifier, cost: variant.cost, metadata: variant.metadata, createdAt: variant.createdAt, updatedAt: variant.updatedAt, ); }