feat(invoice): add invoice json loader
This commit is contained in:
1 parent
d47d138f9a
commit
83cbc85185
1 file changed
+105
@@ -0,0 +1,105 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'invoice.dart';
|
||||||
|
import 'money.dart';
|
||||||
|
|
||||||
|
Invoice invoiceFromJsonString(String source) =>
|
||||||
|
invoiceFromJson(jsonDecode(source) as Map<String, dynamic>);
|
||||||
|
|
||||||
|
Invoice invoiceFromJson(Map<String, dynamic> json) {
|
||||||
|
final currency = Currency.byCode(json['currency'] as String? ?? 'PLN');
|
||||||
|
final linesJson = (json['lines'] as List).cast<Map<String, dynamic>>();
|
||||||
|
final lines = [
|
||||||
|
for (final line in linesJson)
|
||||||
|
InvoiceLine(
|
||||||
|
description: line['description'] as String,
|
||||||
|
quantity: line['quantity'] as num,
|
||||||
|
unitPrice: Money.of((line['unitPrice'] as num).toDouble(), currency),
|
||||||
|
vat: _vatFrom(line['vat']),
|
||||||
|
discountRate: (line['discount'] as num?)?.toDouble() ?? 0.0,
|
||||||
|
unit: line['unit'] as String? ?? 'pcs',
|
||||||
|
),
|
||||||
|
];
|
||||||
|
return Invoice(
|
||||||
|
number: json['number'] as String,
|
||||||
|
issueDate: _parseDate(json['issueDate'] as String),
|
||||||
|
dueDate: json['dueDate'] == null ? null : _parseDate(json['dueDate'] as String),
|
||||||
|
seller: _partyFrom(json['seller'] as Map<String, dynamic>),
|
||||||
|
buyer: _partyFrom(json['buyer'] as Map<String, dynamic>),
|
||||||
|
currency: currency,
|
||||||
|
lines: lines,
|
||||||
|
notes: json['notes'] as String?,
|
||||||
|
paymentTerms: json['paymentTerms'] as String?,
|
||||||
|
reportingCurrency:
|
||||||
|
json['reportingCurrency'] == null ? null : Currency.byCode(json['reportingCurrency'] as String),
|
||||||
|
reportingRate: (json['reportingRate'] as num?)?.toDouble(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
String encodeInvoiceJson(Invoice invoice) {
|
||||||
|
final json = <String, dynamic>{
|
||||||
|
'number': invoice.number,
|
||||||
|
'issueDate': _formatDate(invoice.issueDate),
|
||||||
|
if (invoice.dueDate != null) 'dueDate': _formatDate(invoice.dueDate!),
|
||||||
|
'currency': invoice.currency.code,
|
||||||
|
'seller': _partyToJson(invoice.seller),
|
||||||
|
'buyer': _partyToJson(invoice.buyer),
|
||||||
|
if (invoice.paymentTerms != null) 'paymentTerms': invoice.paymentTerms,
|
||||||
|
if (invoice.notes != null) 'notes': invoice.notes,
|
||||||
|
if (invoice.reportingCurrency != null) 'reportingCurrency': invoice.reportingCurrency!.code,
|
||||||
|
if (invoice.reportingRate != null) 'reportingRate': invoice.reportingRate,
|
||||||
|
'lines': [
|
||||||
|
for (final line in invoice.lines)
|
||||||
|
{
|
||||||
|
'description': line.description,
|
||||||
|
'quantity': line.quantity,
|
||||||
|
'unitPrice': line.unitPrice.amount,
|
||||||
|
'vat': line.vat.rate == 0 ? line.vat.label : (line.vat.rate * 100),
|
||||||
|
if (line.discountRate != 0) 'discount': line.discountRate,
|
||||||
|
'unit': line.unit,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
return const JsonEncoder.withIndent(' ').convert(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
Party _partyFrom(Map<String, dynamic> json) => Party(
|
||||||
|
name: json['name'] as String,
|
||||||
|
address: json['address'] as String?,
|
||||||
|
taxId: json['taxId'] as String?,
|
||||||
|
email: json['email'] as String?,
|
||||||
|
);
|
||||||
|
|
||||||
|
Map<String, dynamic> _partyToJson(Party party) => {
|
||||||
|
'name': party.name,
|
||||||
|
if (party.address != null) 'address': party.address,
|
||||||
|
if (party.taxId != null) 'taxId': party.taxId,
|
||||||
|
if (party.email != null) 'email': party.email,
|
||||||
|
};
|
||||||
|
|
||||||
|
VatRate _vatFrom(Object? value) {
|
||||||
|
if (value is num) return VatRate.fromPercent(value);
|
||||||
|
final label = (value as String).trim().toLowerCase();
|
||||||
|
switch (label) {
|
||||||
|
case 'zw':
|
||||||
|
case 'exempt':
|
||||||
|
return VatRate.exempt;
|
||||||
|
case '0':
|
||||||
|
case '0%':
|
||||||
|
return VatRate.zero;
|
||||||
|
default:
|
||||||
|
final numeric = double.tryParse(label.replaceAll('%', ''));
|
||||||
|
if (numeric != null) return VatRate.fromPercent(numeric);
|
||||||
|
throw FormatException('Unknown VAT rate: $value');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime _parseDate(String text) {
|
||||||
|
final parts = text.split('-');
|
||||||
|
return DateTime(int.parse(parts[0]), int.parse(parts[1]), int.parse(parts[2]));
|
||||||
|
}
|
||||||
|
|
||||||
|
String _formatDate(DateTime date) =>
|
||||||
|
'${date.year.toString().padLeft(4, '0')}-'
|
||||||
|
'${date.month.toString().padLeft(2, '0')}-'
|
||||||
|
'${date.day.toString().padLeft(2, '0')}';
|
||||||
Reference in new issue
Block a user