395 lines
12 KiB
Dart
395 lines
12 KiB
Dart
|
|
import 'package:hesabix_ui/models/account_model.dart';
|
||
|
|
|
||
|
|
/// مدل سند هزینه/درآمد
|
||
|
|
class ExpenseIncomeDocument {
|
||
|
|
final int id;
|
||
|
|
final String code;
|
||
|
|
final String documentType; // "expense" یا "income"
|
||
|
|
final String documentTypeName; // "هزینه" یا "درآمد"
|
||
|
|
final DateTime documentDate;
|
||
|
|
final int currencyId;
|
||
|
|
final String? currencyCode;
|
||
|
|
final double totalAmount;
|
||
|
|
final String? description;
|
||
|
|
final List<ItemLine> itemLines;
|
||
|
|
final List<CounterpartyLine> counterpartyLines;
|
||
|
|
final int itemLinesCount;
|
||
|
|
final int counterpartyLinesCount;
|
||
|
|
final String? createdByName;
|
||
|
|
final DateTime registeredAt;
|
||
|
|
final Map<String, dynamic>? extraInfo;
|
||
|
|
|
||
|
|
const ExpenseIncomeDocument({
|
||
|
|
required this.id,
|
||
|
|
required this.code,
|
||
|
|
required this.documentType,
|
||
|
|
required this.documentTypeName,
|
||
|
|
required this.documentDate,
|
||
|
|
required this.currencyId,
|
||
|
|
this.currencyCode,
|
||
|
|
required this.totalAmount,
|
||
|
|
this.description,
|
||
|
|
required this.itemLines,
|
||
|
|
required this.counterpartyLines,
|
||
|
|
required this.itemLinesCount,
|
||
|
|
required this.counterpartyLinesCount,
|
||
|
|
this.createdByName,
|
||
|
|
required this.registeredAt,
|
||
|
|
this.extraInfo,
|
||
|
|
});
|
||
|
|
|
||
|
|
/// آیا این سند درآمد است؟
|
||
|
|
bool get isIncome => documentType == 'income';
|
||
|
|
|
||
|
|
/// آیا این سند هزینه است؟
|
||
|
|
bool get isExpense => documentType == 'expense';
|
||
|
|
|
||
|
|
/// نام حسابهای آیتمها
|
||
|
|
String? get itemAccountNames {
|
||
|
|
if (itemLines.isEmpty) return null;
|
||
|
|
return itemLines.map((line) => line.accountName).join(', ');
|
||
|
|
}
|
||
|
|
|
||
|
|
/// اطلاعات طرفحسابها
|
||
|
|
String? get counterpartyInfo {
|
||
|
|
if (counterpartyLines.isEmpty) return null;
|
||
|
|
return counterpartyLines.map((line) => line.displayName).join(', ');
|
||
|
|
}
|
||
|
|
|
||
|
|
factory ExpenseIncomeDocument.fromJson(Map<String, dynamic> json) {
|
||
|
|
return ExpenseIncomeDocument(
|
||
|
|
id: json['id'] as int,
|
||
|
|
code: json['code'] as String,
|
||
|
|
documentType: json['document_type'] as String,
|
||
|
|
documentTypeName: json['document_type_name'] as String? ??
|
||
|
|
(json['document_type'] == 'income' ? 'درآمد' : 'هزینه'),
|
||
|
|
documentDate: DateTime.parse(json['document_date'] as String),
|
||
|
|
currencyId: json['currency_id'] as int,
|
||
|
|
currencyCode: json['currency_code'] as String?,
|
||
|
|
totalAmount: (json['total_amount'] as num).toDouble(),
|
||
|
|
description: json['description'] as String?,
|
||
|
|
itemLines: (json['item_lines'] as List<dynamic>?)
|
||
|
|
?.map((line) => ItemLine.fromJson(line as Map<String, dynamic>))
|
||
|
|
.toList() ?? [],
|
||
|
|
counterpartyLines: (json['counterparty_lines'] as List<dynamic>?)
|
||
|
|
?.map((line) => CounterpartyLine.fromJson(line as Map<String, dynamic>))
|
||
|
|
.toList() ?? [],
|
||
|
|
itemLinesCount: json['item_lines_count'] as int? ?? 0,
|
||
|
|
counterpartyLinesCount: json['counterparty_lines_count'] as int? ?? 0,
|
||
|
|
createdByName: json['created_by_name'] as String?,
|
||
|
|
registeredAt: DateTime.parse(json['registered_at'] as String),
|
||
|
|
extraInfo: json['extra_info'] as Map<String, dynamic>?,
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
Map<String, dynamic> toJson() {
|
||
|
|
return {
|
||
|
|
'id': id,
|
||
|
|
'code': code,
|
||
|
|
'document_type': documentType,
|
||
|
|
'document_type_name': documentTypeName,
|
||
|
|
'document_date': documentDate.toIso8601String(),
|
||
|
|
'currency_id': currencyId,
|
||
|
|
'currency_code': currencyCode,
|
||
|
|
'total_amount': totalAmount,
|
||
|
|
'description': description,
|
||
|
|
'item_lines': itemLines.map((line) => line.toJson()).toList(),
|
||
|
|
'counterparty_lines': counterpartyLines.map((line) => line.toJson()).toList(),
|
||
|
|
'item_lines_count': itemLinesCount,
|
||
|
|
'counterparty_lines_count': counterpartyLinesCount,
|
||
|
|
'created_by_name': createdByName,
|
||
|
|
'registered_at': registeredAt.toIso8601String(),
|
||
|
|
'extra_info': extraInfo,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// خط آیتم (حساب هزینه/درآمد)
|
||
|
|
class ItemLine {
|
||
|
|
final int id;
|
||
|
|
final int accountId;
|
||
|
|
final String accountCode;
|
||
|
|
final String accountName;
|
||
|
|
final double amount;
|
||
|
|
final String? description;
|
||
|
|
|
||
|
|
const ItemLine({
|
||
|
|
required this.id,
|
||
|
|
required this.accountId,
|
||
|
|
required this.accountCode,
|
||
|
|
required this.accountName,
|
||
|
|
required this.amount,
|
||
|
|
this.description,
|
||
|
|
});
|
||
|
|
|
||
|
|
factory ItemLine.fromJson(Map<String, dynamic> json) {
|
||
|
|
return ItemLine(
|
||
|
|
id: json['id'] as int,
|
||
|
|
accountId: json['account_id'] as int,
|
||
|
|
accountCode: json['account_code'] as String,
|
||
|
|
accountName: json['account_name'] as String,
|
||
|
|
amount: (json['amount'] as num).toDouble(),
|
||
|
|
description: json['description'] as String?,
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
Map<String, dynamic> toJson() {
|
||
|
|
return {
|
||
|
|
'id': id,
|
||
|
|
'account_id': accountId,
|
||
|
|
'account_code': accountCode,
|
||
|
|
'account_name': accountName,
|
||
|
|
'amount': amount,
|
||
|
|
'description': description,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// خط طرفحساب
|
||
|
|
class CounterpartyLine {
|
||
|
|
final int id;
|
||
|
|
final String transactionType;
|
||
|
|
final String transactionTypeName;
|
||
|
|
final double amount;
|
||
|
|
final DateTime transactionDate;
|
||
|
|
final String? description;
|
||
|
|
final double? commission;
|
||
|
|
|
||
|
|
// فیلدهای اختیاری بر اساس نوع تراکنش
|
||
|
|
final int? bankAccountId;
|
||
|
|
final String? bankAccountName;
|
||
|
|
final int? cashRegisterId;
|
||
|
|
final String? cashRegisterName;
|
||
|
|
final int? pettyCashId;
|
||
|
|
final String? pettyCashName;
|
||
|
|
final int? checkId;
|
||
|
|
final String? checkNumber;
|
||
|
|
final int? personId;
|
||
|
|
final String? personName;
|
||
|
|
|
||
|
|
const CounterpartyLine({
|
||
|
|
required this.id,
|
||
|
|
required this.transactionType,
|
||
|
|
required this.transactionTypeName,
|
||
|
|
required this.amount,
|
||
|
|
required this.transactionDate,
|
||
|
|
this.description,
|
||
|
|
this.commission,
|
||
|
|
this.bankAccountId,
|
||
|
|
this.bankAccountName,
|
||
|
|
this.cashRegisterId,
|
||
|
|
this.cashRegisterName,
|
||
|
|
this.pettyCashId,
|
||
|
|
this.pettyCashName,
|
||
|
|
this.checkId,
|
||
|
|
this.checkNumber,
|
||
|
|
this.personId,
|
||
|
|
this.personName,
|
||
|
|
});
|
||
|
|
|
||
|
|
/// نام نمایشی طرفحساب
|
||
|
|
String get displayName {
|
||
|
|
switch (transactionType) {
|
||
|
|
case 'bank':
|
||
|
|
return bankAccountName ?? 'حساب بانکی';
|
||
|
|
case 'cash_register':
|
||
|
|
return cashRegisterName ?? 'صندوق';
|
||
|
|
case 'petty_cash':
|
||
|
|
return pettyCashName ?? 'تنخواهگردان';
|
||
|
|
case 'check':
|
||
|
|
return checkNumber != null ? 'چک $checkNumber' : 'چک';
|
||
|
|
case 'person':
|
||
|
|
return personName ?? 'شخص';
|
||
|
|
default:
|
||
|
|
return transactionTypeName;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
factory CounterpartyLine.fromJson(Map<String, dynamic> json) {
|
||
|
|
return CounterpartyLine(
|
||
|
|
id: json['id'] as int,
|
||
|
|
transactionType: json['transaction_type'] as String,
|
||
|
|
transactionTypeName: json['transaction_type_name'] as String? ??
|
||
|
|
_getTransactionTypeName(json['transaction_type'] as String),
|
||
|
|
amount: (json['amount'] as num).toDouble(),
|
||
|
|
transactionDate: DateTime.parse(json['transaction_date'] as String),
|
||
|
|
description: json['description'] as String?,
|
||
|
|
commission: json['commission'] != null ? (json['commission'] as num).toDouble() : null,
|
||
|
|
bankAccountId: json['bank_account_id'] as int?,
|
||
|
|
bankAccountName: json['bank_account_name'] as String?,
|
||
|
|
cashRegisterId: json['cash_register_id'] as int?,
|
||
|
|
cashRegisterName: json['cash_register_name'] as String?,
|
||
|
|
pettyCashId: json['petty_cash_id'] as int?,
|
||
|
|
pettyCashName: json['petty_cash_name'] as String?,
|
||
|
|
checkId: json['check_id'] as int?,
|
||
|
|
checkNumber: json['check_number'] as String?,
|
||
|
|
personId: json['person_id'] as int?,
|
||
|
|
personName: json['person_name'] as String?,
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
Map<String, dynamic> toJson() {
|
||
|
|
return {
|
||
|
|
'id': id,
|
||
|
|
'transaction_type': transactionType,
|
||
|
|
'transaction_type_name': transactionTypeName,
|
||
|
|
'amount': amount,
|
||
|
|
'transaction_date': transactionDate.toIso8601String(),
|
||
|
|
'description': description,
|
||
|
|
'commission': commission,
|
||
|
|
'bank_account_id': bankAccountId,
|
||
|
|
'bank_account_name': bankAccountName,
|
||
|
|
'cash_register_id': cashRegisterId,
|
||
|
|
'cash_register_name': cashRegisterName,
|
||
|
|
'petty_cash_id': pettyCashId,
|
||
|
|
'petty_cash_name': pettyCashName,
|
||
|
|
'check_id': checkId,
|
||
|
|
'check_number': checkNumber,
|
||
|
|
'person_id': personId,
|
||
|
|
'person_name': personName,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
static String _getTransactionTypeName(String type) {
|
||
|
|
switch (type) {
|
||
|
|
case 'bank':
|
||
|
|
return 'بانک';
|
||
|
|
case 'cash_register':
|
||
|
|
return 'صندوق';
|
||
|
|
case 'petty_cash':
|
||
|
|
return 'تنخواهگردان';
|
||
|
|
case 'check':
|
||
|
|
return 'چک';
|
||
|
|
case 'person':
|
||
|
|
return 'شخص';
|
||
|
|
default:
|
||
|
|
return type;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// نوع تراکنش برای فرم
|
||
|
|
enum TransactionType {
|
||
|
|
bank('bank', 'بانک'),
|
||
|
|
cashRegister('cash_register', 'صندوق'),
|
||
|
|
pettyCash('petty_cash', 'تنخواهگردان'),
|
||
|
|
check('check', 'چک'),
|
||
|
|
person('person', 'شخص');
|
||
|
|
|
||
|
|
const TransactionType(this.value, this.displayName);
|
||
|
|
|
||
|
|
final String value;
|
||
|
|
final String displayName;
|
||
|
|
|
||
|
|
static TransactionType? fromValue(String value) {
|
||
|
|
for (final type in TransactionType.values) {
|
||
|
|
if (type.value == value) return type;
|
||
|
|
}
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// دادههای خط آیتم برای فرم
|
||
|
|
class ItemLineData {
|
||
|
|
final int? accountId;
|
||
|
|
final String? accountName;
|
||
|
|
final double amount;
|
||
|
|
final String? description;
|
||
|
|
|
||
|
|
const ItemLineData({
|
||
|
|
this.accountId,
|
||
|
|
this.accountName,
|
||
|
|
required this.amount,
|
||
|
|
this.description,
|
||
|
|
});
|
||
|
|
|
||
|
|
ItemLineData copyWith({
|
||
|
|
int? accountId,
|
||
|
|
String? accountName,
|
||
|
|
double? amount,
|
||
|
|
String? description,
|
||
|
|
}) {
|
||
|
|
return ItemLineData(
|
||
|
|
accountId: accountId ?? this.accountId,
|
||
|
|
accountName: accountName ?? this.accountName,
|
||
|
|
amount: amount ?? this.amount,
|
||
|
|
description: description ?? this.description,
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/// دادههای خط طرفحساب برای فرم
|
||
|
|
class CounterpartyLineData {
|
||
|
|
final TransactionType transactionType;
|
||
|
|
final double amount;
|
||
|
|
final DateTime transactionDate;
|
||
|
|
final String? description;
|
||
|
|
final double? commission;
|
||
|
|
|
||
|
|
// فیلدهای اختیاری بر اساس نوع تراکنش
|
||
|
|
final int? bankAccountId;
|
||
|
|
final String? bankAccountName;
|
||
|
|
final int? cashRegisterId;
|
||
|
|
final String? cashRegisterName;
|
||
|
|
final int? pettyCashId;
|
||
|
|
final String? pettyCashName;
|
||
|
|
final int? checkId;
|
||
|
|
final String? checkNumber;
|
||
|
|
final int? personId;
|
||
|
|
final String? personName;
|
||
|
|
|
||
|
|
const CounterpartyLineData({
|
||
|
|
required this.transactionType,
|
||
|
|
required this.amount,
|
||
|
|
required this.transactionDate,
|
||
|
|
this.description,
|
||
|
|
this.commission,
|
||
|
|
this.bankAccountId,
|
||
|
|
this.bankAccountName,
|
||
|
|
this.cashRegisterId,
|
||
|
|
this.cashRegisterName,
|
||
|
|
this.pettyCashId,
|
||
|
|
this.pettyCashName,
|
||
|
|
this.checkId,
|
||
|
|
this.checkNumber,
|
||
|
|
this.personId,
|
||
|
|
this.personName,
|
||
|
|
});
|
||
|
|
|
||
|
|
CounterpartyLineData copyWith({
|
||
|
|
TransactionType? transactionType,
|
||
|
|
double? amount,
|
||
|
|
DateTime? transactionDate,
|
||
|
|
String? description,
|
||
|
|
double? commission,
|
||
|
|
int? bankAccountId,
|
||
|
|
String? bankAccountName,
|
||
|
|
int? cashRegisterId,
|
||
|
|
String? cashRegisterName,
|
||
|
|
int? pettyCashId,
|
||
|
|
String? pettyCashName,
|
||
|
|
int? checkId,
|
||
|
|
String? checkNumber,
|
||
|
|
int? personId,
|
||
|
|
String? personName,
|
||
|
|
}) {
|
||
|
|
return CounterpartyLineData(
|
||
|
|
transactionType: transactionType ?? this.transactionType,
|
||
|
|
amount: amount ?? this.amount,
|
||
|
|
transactionDate: transactionDate ?? this.transactionDate,
|
||
|
|
description: description ?? this.description,
|
||
|
|
commission: commission ?? this.commission,
|
||
|
|
bankAccountId: bankAccountId ?? this.bankAccountId,
|
||
|
|
bankAccountName: bankAccountName ?? this.bankAccountName,
|
||
|
|
cashRegisterId: cashRegisterId ?? this.cashRegisterId,
|
||
|
|
cashRegisterName: cashRegisterName ?? this.cashRegisterName,
|
||
|
|
pettyCashId: pettyCashId ?? this.pettyCashId,
|
||
|
|
pettyCashName: pettyCashName ?? this.pettyCashName,
|
||
|
|
checkId: checkId ?? this.checkId,
|
||
|
|
checkNumber: checkNumber ?? this.checkNumber,
|
||
|
|
personId: personId ?? this.personId,
|
||
|
|
personName: personName ?? this.personName,
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|