feat: dukung penjualan produk per timbangan
Produk kini punya cara jual `unit` (cacah) atau `weight` (timbangan), mengikuti kontrak backend di docs/integration-weight-based-products.md. - tipe SellBy, domain/infrastructure unit baru, dan endpoint /api/v1/units - dialog input berat saat produk timbangan ditambahkan ke keranjang - tiap penimbangan jadi baris keranjang sendiri; total baris dihitung berat x harga satuan, sedangkan produk cacah tetap digabung - request ke backend mengirim quantity 1 dan membawa berat - migrasi DB v3: kolom sell_by, unit_id, unit_name, unit_abbreviation di tabel products supaya satuan tetap tampil saat offline - tampilan keranjang, struk, split bill, void, dan refund memakai berat - test/weight_based_products_test.dart menutup perilaku di atas (9 test) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,25 @@ class ListProductDto with _$ListProductDto {
|
||||
);
|
||||
}
|
||||
|
||||
/// 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<String, dynamic> json) =>
|
||||
_$ProductUnitDtoFromJson(json);
|
||||
}
|
||||
|
||||
@freezed
|
||||
class ProductDto with _$ProductDto {
|
||||
const ProductDto._();
|
||||
@@ -46,11 +65,28 @@ class ProductDto with _$ProductDto {
|
||||
@JsonKey(name: "created_at") String? createdAt,
|
||||
@JsonKey(name: "updated_at") String? updatedAt,
|
||||
@JsonKey(name: "variants") List<ProductVariantDto>? 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<String, dynamic> 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 ?? '',
|
||||
@@ -70,6 +106,10 @@ class ProductDto with _$ProductDto {
|
||||
createdAt: createdAt ?? '',
|
||||
updatedAt: updatedAt ?? '',
|
||||
variants: variants?.map((v) => v.toDomain()).toList() ?? [],
|
||||
sellBy: SellBy.normalize(sellBy),
|
||||
unitId: _resolvedUnitId,
|
||||
unitName: _resolvedUnitName,
|
||||
unitAbbreviation: _resolvedUnitAbbreviation,
|
||||
);
|
||||
|
||||
Map<String, dynamic> toMap() => {
|
||||
@@ -89,6 +129,10 @@ class ProductDto with _$ProductDto {
|
||||
'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(
|
||||
@@ -117,6 +161,10 @@ class ProductDto with _$ProductDto {
|
||||
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(
|
||||
@@ -139,6 +187,10 @@ class ProductDto with _$ProductDto {
|
||||
variants: product.variants
|
||||
.map((v) => ProductVariantDto.fromDomain(v))
|
||||
.toList(),
|
||||
sellBy: product.sellBy,
|
||||
unitId: product.unitId,
|
||||
unitName: product.unitName,
|
||||
unitAbbreviation: product.unitAbbreviation,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user