update payment

This commit is contained in:
Phuoc Nguyen
2025-12-01 16:07:49 +07:00
parent e62c466155
commit 12bd70479c
10 changed files with 796 additions and 136 deletions

View File

@@ -0,0 +1,80 @@
/// Payment Remote Data Source
///
/// Handles API calls for payment-related data.
library;
import 'package:worker/core/constants/api_constants.dart';
import 'package:worker/core/network/dio_client.dart';
import 'package:worker/features/orders/data/models/payment_model.dart';
/// Payment Remote Data Source
class PaymentRemoteDataSource {
const PaymentRemoteDataSource(this._dioClient);
final DioClient _dioClient;
/// Get payments list
///
/// Calls: POST /api/method/building_material.building_material.api.payment.get_list
/// Returns: List of payments
Future<List<PaymentModel>> getPaymentsList({
int limitStart = 0,
int limitPageLength = 0,
}) async {
try {
final response = await _dioClient.post<Map<String, dynamic>>(
'${ApiConstants.frappeApiMethod}${ApiConstants.getPaymentList}',
data: {
'limit_start': limitStart,
'limit_page_length': limitPageLength,
},
);
final data = response.data;
if (data == null) {
throw Exception('No data received from getPaymentsList API');
}
// API returns: { "message": [...] }
final message = data['message'];
if (message == null) {
throw Exception('No message field in getPaymentsList response');
}
final List<dynamic> paymentsList = message as List<dynamic>;
return paymentsList
.map((json) => PaymentModel.fromJson(json as Map<String, dynamic>))
.toList();
} catch (e) {
throw Exception('Failed to get payments list: $e');
}
}
/// Get payment detail
///
/// Calls: POST /api/method/building_material.building_material.api.payment.get_detail
/// Returns: Payment detail
Future<PaymentModel> getPaymentDetail(String name) async {
try {
final response = await _dioClient.post<Map<String, dynamic>>(
'${ApiConstants.frappeApiMethod}${ApiConstants.getPaymentDetail}',
data: {'name': name},
);
final data = response.data;
if (data == null) {
throw Exception('No data received from getPaymentDetail API');
}
// API returns: { "message": {...} }
final message = data['message'];
if (message == null) {
throw Exception('No message field in getPaymentDetail response');
}
return PaymentModel.fromJson(message as Map<String, dynamic>);
} catch (e) {
throw Exception('Failed to get payment detail: $e');
}
}
}

View File

@@ -0,0 +1,92 @@
/// Data Model: Payment Model
///
/// Model for payment data with API serialization.
/// Not stored in local database.
library;
import 'package:worker/features/orders/domain/entities/payment.dart';
/// Payment Model
///
/// Model for API parsing only (no Hive storage).
class PaymentModel {
/// Payment ID (e.g., "ACC-PAY-2025-00020")
final String name;
/// Payment posting date (stored as ISO string)
final String postingDate;
/// Amount paid
final double paidAmount;
/// Payment method (e.g., "Chuyển khoản")
final String? modeOfPayment;
/// Related invoice ID
final String? invoiceId;
/// Related order ID
final String? orderId;
const PaymentModel({
required this.name,
required this.postingDate,
required this.paidAmount,
this.modeOfPayment,
this.invoiceId,
this.orderId,
});
/// Create from JSON (API response)
factory PaymentModel.fromJson(Map<String, dynamic> json) {
return PaymentModel(
name: json['name'] as String? ?? '',
postingDate: json['posting_date'] as String? ?? '',
paidAmount: (json['paid_amount'] as num?)?.toDouble() ?? 0.0,
modeOfPayment: json['mode_of_payment'] as String?,
invoiceId: json['invoice_id'] as String?,
orderId: json['order_id'] as String?,
);
}
/// Convert to JSON
Map<String, dynamic> toJson() {
return {
'name': name,
'posting_date': postingDate,
'paid_amount': paidAmount,
'mode_of_payment': modeOfPayment,
'invoice_id': invoiceId,
'order_id': orderId,
};
}
/// Convert to domain entity
Payment toEntity() {
return Payment(
name: name,
postingDate: DateTime.tryParse(postingDate) ?? DateTime.now(),
paidAmount: paidAmount,
modeOfPayment: modeOfPayment,
invoiceId: invoiceId,
orderId: orderId,
);
}
/// Create from domain entity
factory PaymentModel.fromEntity(Payment entity) {
return PaymentModel(
name: entity.name,
postingDate: entity.postingDate.toIso8601String().split('T').first,
paidAmount: entity.paidAmount,
modeOfPayment: entity.modeOfPayment,
invoiceId: entity.invoiceId,
orderId: entity.orderId,
);
}
@override
String toString() {
return 'PaymentModel(name: $name, paidAmount: $paidAmount)';
}
}

View File

@@ -0,0 +1,43 @@
/// Payment Repository Implementation
///
/// Implements the payment repository interface.
library;
import 'package:worker/features/orders/data/datasources/payment_remote_datasource.dart';
import 'package:worker/features/orders/domain/entities/payment.dart';
import 'package:worker/features/orders/domain/repositories/payment_repository.dart';
/// Payment Repository Implementation
class PaymentRepositoryImpl implements PaymentRepository {
const PaymentRepositoryImpl(this._remoteDataSource);
final PaymentRemoteDataSource _remoteDataSource;
@override
Future<List<Payment>> getPaymentsList({
int limitStart = 0,
int limitPageLength = 0,
}) async {
try {
final paymentsData = await _remoteDataSource.getPaymentsList(
limitStart: limitStart,
limitPageLength: limitPageLength,
);
// Convert Model → Entity
return paymentsData.map((model) => model.toEntity()).toList();
} catch (e) {
throw Exception('Failed to get payments list: $e');
}
}
@override
Future<Payment> getPaymentDetail(String name) async {
try {
final paymentData = await _remoteDataSource.getPaymentDetail(name);
// Convert Model → Entity
return paymentData.toEntity();
} catch (e) {
throw Exception('Failed to get payment detail: $e');
}
}
}