416 lines
12 KiB
Dart
416 lines
12 KiB
Dart
enum ProductType {
|
|
simple,
|
|
variable,
|
|
grouped,
|
|
external,
|
|
digital, // specific logic might be needed, often just 'simple' + virtual/downloadable properties
|
|
downloadable, // usually property of simple/variable
|
|
virtual, // usually property of simple/variable
|
|
subscription,
|
|
variableSubscription, // 'variable-subscription'
|
|
bundle,
|
|
composite,
|
|
bookable,
|
|
unknown,
|
|
}
|
|
|
|
abstract class Product {
|
|
final int id;
|
|
final String name;
|
|
final ProductType type;
|
|
final String status; // publish, private, draft, pending, future
|
|
final String? sku;
|
|
final String? price;
|
|
final String? regularPrice;
|
|
final String? salePrice;
|
|
final String stockStatus; // instock, outofstock, onbackorder
|
|
final bool manageStock;
|
|
final int? stockQuantity;
|
|
final List<ProductImage> images;
|
|
final String description;
|
|
final String shortDescription;
|
|
final List<dynamic> metaData;
|
|
|
|
Product({
|
|
required this.id,
|
|
required this.name,
|
|
required this.type,
|
|
required this.status,
|
|
this.sku,
|
|
this.price,
|
|
this.regularPrice,
|
|
this.salePrice,
|
|
required this.stockStatus,
|
|
this.manageStock = false,
|
|
this.stockQuantity,
|
|
this.images = const [],
|
|
this.description = '',
|
|
this.shortDescription = '',
|
|
this.metaData = const [],
|
|
});
|
|
|
|
factory Product.fromJson(Map<String, dynamic> json) {
|
|
final typeStr = json['type'] as String? ?? 'simple';
|
|
final type = _parseType(typeStr);
|
|
|
|
switch (type) {
|
|
case ProductType.variable:
|
|
return VariableProduct.fromJson(json, type);
|
|
case ProductType.grouped:
|
|
return GroupedProduct.fromJson(json, type);
|
|
case ProductType.external:
|
|
return ExternalProduct.fromJson(json, type);
|
|
// Add other specific classes as needed.
|
|
// For now, map others to SimpleProduct or a specific generic fallback if they don't have unique fields we critically need right now.
|
|
default:
|
|
// 'simple', 'booking', 'subscription', etc. unless they get their own class
|
|
return SimpleProduct.fromJson(json, type);
|
|
}
|
|
}
|
|
|
|
static ProductType _parseType(String type) {
|
|
switch (type) {
|
|
case 'simple': return ProductType.simple;
|
|
case 'variable': return ProductType.variable;
|
|
case 'grouped': return ProductType.grouped;
|
|
case 'external': return ProductType.external;
|
|
case 'subscription': return ProductType.subscription;
|
|
case 'variable-subscription': return ProductType.variableSubscription;
|
|
case 'bundle': return ProductType.bundle;
|
|
case 'composite': return ProductType.composite;
|
|
case 'booking': return ProductType.bookable;
|
|
default: return ProductType.unknown;
|
|
}
|
|
}
|
|
|
|
Map<String, dynamic> toJson() {
|
|
return {
|
|
'id': id,
|
|
'name': name,
|
|
'type': _typeToString(type),
|
|
'status': status,
|
|
'sku': sku,
|
|
'regular_price': regularPrice,
|
|
'sale_price': salePrice,
|
|
'stock_status': stockStatus,
|
|
'manage_stock': manageStock,
|
|
'stock_quantity': stockQuantity,
|
|
'images': images.map((i) => i.toJson()).toList(),
|
|
'description': description,
|
|
'short_description': shortDescription,
|
|
'meta_data': metaData,
|
|
};
|
|
}
|
|
|
|
String _typeToString(ProductType t) {
|
|
// simplified reverse mapping
|
|
switch (t) {
|
|
case ProductType.simple: return 'simple';
|
|
case ProductType.variable: return 'variable';
|
|
case ProductType.grouped: return 'grouped';
|
|
case ProductType.external: return 'external';
|
|
case ProductType.subscription: return 'subscription';
|
|
case ProductType.variableSubscription: return 'variable-subscription';
|
|
case ProductType.bundle: return 'bundle';
|
|
case ProductType.composite: return 'composite';
|
|
case ProductType.bookable: return 'booking';
|
|
default: return 'simple';
|
|
}
|
|
}
|
|
}
|
|
|
|
class ProductImage {
|
|
final int id;
|
|
final String src;
|
|
final String name;
|
|
final String alt;
|
|
|
|
ProductImage({
|
|
required this.id,
|
|
required this.src,
|
|
required this.name,
|
|
required this.alt,
|
|
});
|
|
|
|
factory ProductImage.fromJson(Map<String, dynamic> json) {
|
|
return ProductImage(
|
|
id: json['id'] ?? 0,
|
|
src: json['src'] ?? '',
|
|
name: json['name'] ?? '',
|
|
alt: json['alt'] ?? '',
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'id': id,
|
|
'src': src,
|
|
'name': name,
|
|
'alt': alt,
|
|
};
|
|
}
|
|
|
|
class SimpleProduct extends Product {
|
|
final bool virtual;
|
|
final bool downloadable;
|
|
|
|
SimpleProduct({
|
|
required super.id,
|
|
required super.name,
|
|
required super.type,
|
|
required super.status,
|
|
super.sku,
|
|
super.price,
|
|
super.regularPrice,
|
|
super.salePrice,
|
|
required super.stockStatus,
|
|
super.manageStock,
|
|
super.stockQuantity,
|
|
super.images,
|
|
super.description,
|
|
super.shortDescription,
|
|
super.metaData,
|
|
this.virtual = false,
|
|
this.downloadable = false,
|
|
});
|
|
|
|
factory SimpleProduct.fromJson(Map<String, dynamic> json, ProductType type) {
|
|
return SimpleProduct(
|
|
id: json['id'],
|
|
name: json['name'] ?? '',
|
|
type: type,
|
|
status: json['status'] ?? 'publish',
|
|
sku: json['sku'],
|
|
price: json['price']?.toString(), // API returns string or number? Usually string in WC
|
|
regularPrice: json['regular_price']?.toString(),
|
|
salePrice: json['sale_price']?.toString(),
|
|
stockStatus: json['stock_status'] ?? 'instock',
|
|
manageStock: json['manage_stock'] ?? false,
|
|
stockQuantity: json['stock_quantity'],
|
|
images: (json['images'] as List?)?.map((e) => ProductImage.fromJson(e)).toList() ?? [],
|
|
description: json['description'] ?? '',
|
|
shortDescription: json['short_description'] ?? '',
|
|
metaData: List.from(json['meta_data'] ?? []),
|
|
virtual: json['virtual'] ?? false,
|
|
downloadable: json['downloadable'] ?? false,
|
|
);
|
|
}
|
|
|
|
@override
|
|
Map<String, dynamic> toJson() {
|
|
final m = super.toJson();
|
|
m['virtual'] = virtual;
|
|
m['downloadable'] = downloadable;
|
|
return m;
|
|
}
|
|
}
|
|
|
|
class VariableProduct extends Product {
|
|
final List<int> variations;
|
|
|
|
VariableProduct({
|
|
required super.id,
|
|
required super.name,
|
|
required super.type,
|
|
required super.status,
|
|
super.sku,
|
|
super.price,
|
|
super.regularPrice,
|
|
super.salePrice,
|
|
required super.stockStatus,
|
|
super.manageStock,
|
|
super.stockQuantity,
|
|
super.images,
|
|
super.description,
|
|
super.shortDescription,
|
|
super.metaData,
|
|
this.variations = const [],
|
|
});
|
|
|
|
factory VariableProduct.fromJson(Map<String, dynamic> json, ProductType type) {
|
|
return VariableProduct(
|
|
id: json['id'],
|
|
name: json['name'] ?? '',
|
|
type: type,
|
|
status: json['status'] ?? 'publish',
|
|
sku: json['sku'],
|
|
price: json['price']?.toString(),
|
|
regularPrice: json['regular_price']?.toString(),
|
|
salePrice: json['sale_price']?.toString(),
|
|
stockStatus: json['stock_status'] ?? 'instock',
|
|
manageStock: json['manage_stock'] ?? false,
|
|
stockQuantity: json['stock_quantity'],
|
|
images: (json['images'] as List?)?.map((e) => ProductImage.fromJson(e)).toList() ?? [],
|
|
description: json['description'] ?? '',
|
|
shortDescription: json['short_description'] ?? '',
|
|
metaData: List.from(json['meta_data'] ?? []),
|
|
variations: (json['variations'] as List?)?.cast<int>() ?? [],
|
|
);
|
|
}
|
|
|
|
@override
|
|
Map<String, dynamic> toJson() {
|
|
final m = super.toJson();
|
|
m['variations'] = variations;
|
|
return m;
|
|
}
|
|
}
|
|
|
|
class Variation {
|
|
final int id;
|
|
final String sku;
|
|
final String? price;
|
|
final String? regularPrice;
|
|
final String? salePrice;
|
|
final String stockStatus;
|
|
final bool manageStock;
|
|
final int? stockQuantity;
|
|
final List<Map<String, dynamic>> attributes; // e.g. [{id: 0, name: 'Color', option: 'Blue'}]
|
|
final ProductImage? image;
|
|
|
|
Variation({
|
|
required this.id,
|
|
this.sku = '',
|
|
this.price,
|
|
this.regularPrice,
|
|
this.salePrice,
|
|
this.stockStatus = 'instock',
|
|
this.manageStock = false,
|
|
this.stockQuantity,
|
|
this.attributes = const [],
|
|
this.image,
|
|
});
|
|
|
|
factory Variation.fromJson(Map<String, dynamic> json) {
|
|
return Variation(
|
|
id: json['id'],
|
|
sku: json['sku'] ?? '',
|
|
price: json['price']?.toString(),
|
|
regularPrice: json['regular_price']?.toString(),
|
|
salePrice: json['sale_price']?.toString(),
|
|
stockStatus: json['stock_status'] ?? 'instock',
|
|
manageStock: json['manage_stock'] ?? false,
|
|
stockQuantity: json['stock_quantity'],
|
|
attributes: List<Map<String, dynamic>>.from(json['attributes'] ?? []),
|
|
image: json['image'] != null ? ProductImage.fromJson(json['image']) : null,
|
|
);
|
|
}
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'id': id,
|
|
'sku': sku,
|
|
'regular_price': regularPrice,
|
|
'sale_price': salePrice,
|
|
'stock_status': stockStatus,
|
|
'manage_stock': manageStock,
|
|
'stock_quantity': stockQuantity,
|
|
'attributes': attributes,
|
|
'image': image?.toJson(),
|
|
};
|
|
}
|
|
|
|
class GroupedProduct extends Product {
|
|
final List<int> groupedProducts;
|
|
|
|
GroupedProduct({
|
|
required super.id,
|
|
required super.name,
|
|
required super.type,
|
|
required super.status,
|
|
super.sku,
|
|
super.price,
|
|
super.regularPrice,
|
|
super.salePrice,
|
|
required super.stockStatus,
|
|
super.manageStock,
|
|
super.stockQuantity,
|
|
super.images,
|
|
super.description,
|
|
super.shortDescription,
|
|
super.metaData,
|
|
this.groupedProducts = const [],
|
|
});
|
|
|
|
factory GroupedProduct.fromJson(Map<String, dynamic> json, ProductType type) {
|
|
return GroupedProduct(
|
|
id: json['id'],
|
|
name: json['name'] ?? '',
|
|
type: type,
|
|
status: json['status'] ?? 'publish',
|
|
sku: json['sku'],
|
|
price: json['price']?.toString(),
|
|
regularPrice: json['regular_price']?.toString(),
|
|
salePrice: json['sale_price']?.toString(),
|
|
stockStatus: json['stock_status'] ?? 'instock',
|
|
manageStock: json['manage_stock'] ?? false,
|
|
stockQuantity: json['stock_quantity'],
|
|
images: (json['images'] as List?)?.map((e) => ProductImage.fromJson(e)).toList() ?? [],
|
|
description: json['description'] ?? '',
|
|
shortDescription: json['short_description'] ?? '',
|
|
metaData: List.from(json['meta_data'] ?? []),
|
|
groupedProducts: (json['grouped_products'] as List?)?.cast<int>() ?? [],
|
|
);
|
|
}
|
|
|
|
@override
|
|
Map<String, dynamic> toJson() {
|
|
final m = super.toJson();
|
|
m['grouped_products'] = groupedProducts;
|
|
return m;
|
|
}
|
|
}
|
|
|
|
class ExternalProduct extends Product {
|
|
final String externalUrl;
|
|
final String buttonText;
|
|
|
|
ExternalProduct({
|
|
required super.id,
|
|
required super.name,
|
|
required super.type,
|
|
required super.status,
|
|
super.sku,
|
|
super.price,
|
|
super.regularPrice,
|
|
super.salePrice,
|
|
required super.stockStatus,
|
|
super.manageStock,
|
|
super.stockQuantity,
|
|
super.images,
|
|
super.description,
|
|
super.shortDescription,
|
|
super.metaData,
|
|
this.externalUrl = '',
|
|
this.buttonText = '',
|
|
});
|
|
|
|
factory ExternalProduct.fromJson(Map<String, dynamic> json, ProductType type) {
|
|
return ExternalProduct(
|
|
id: json['id'],
|
|
name: json['name'] ?? '',
|
|
type: type,
|
|
status: json['status'] ?? 'publish',
|
|
sku: json['sku'],
|
|
price: json['price']?.toString(),
|
|
regularPrice: json['regular_price']?.toString(),
|
|
salePrice: json['sale_price']?.toString(),
|
|
stockStatus: json['stock_status'] ?? 'instock',
|
|
manageStock: json['manage_stock'] ?? false,
|
|
stockQuantity: json['stock_quantity'],
|
|
images: (json['images'] as List?)?.map((e) => ProductImage.fromJson(e)).toList() ?? [],
|
|
description: json['description'] ?? '',
|
|
shortDescription: json['short_description'] ?? '',
|
|
metaData: List.from(json['meta_data'] ?? []),
|
|
externalUrl: json['external_url'] ?? '',
|
|
buttonText: json['button_text'] ?? '',
|
|
);
|
|
}
|
|
|
|
@override
|
|
Map<String, dynamic> toJson() {
|
|
final m = super.toJson();
|
|
m['external_url'] = externalUrl;
|
|
m['button_text'] = buttonText;
|
|
return m;
|
|
}
|
|
}
|