feat: implement idempotency key for critical API endpoints

This commit is contained in:
Efril
2026-06-04 00:48:50 +07:00
parent 2ab20a1150
commit b228538725
21 changed files with 431 additions and 37 deletions
@@ -18,6 +18,15 @@ class OrderRemoteDataProvider {
final _logName = 'OrderRemoteDataProvider';
OrderRemoteDataProvider(this._apiClient);
/// Helper untuk merge auth header dengan idempotency key
Map<String, dynamic> _buildHeaders({String? idempotencyKey}) {
final headers = getAuthorizationHeader();
if (idempotencyKey != null) {
headers['X-Idempotency-Key'] = idempotencyKey;
}
return headers;
}
Future<DC<OrderFailure, ListOrderDto>> fetchOrders({
int page = 1,
int limit = 10,
@@ -151,13 +160,14 @@ class OrderRemoteDataProvider {
}
Future<DC<OrderFailure, PaymentDto>> storePayment(
PaymentRequestDto request,
) async {
PaymentRequestDto request, {
String? idempotencyKey,
}) async {
try {
final response = await _apiClient.post(
ApiPath.payments,
data: request.toJson(),
headers: getAuthorizationHeader(),
headers: _buildHeaders(idempotencyKey: idempotencyKey),
);
if (response.data['success'] == false) {
@@ -178,6 +188,7 @@ class OrderRemoteDataProvider {
Future<DC<OrderFailure, OrderDto>> addItemOrder({
required String id,
required List<AddItemOrderRequestDto> request,
String? idempotencyKey,
}) async {
try {
final response = await _apiClient.post(
@@ -186,7 +197,7 @@ class OrderRemoteDataProvider {
'notes': '',
'order_items': request.map((e) => e.toRequest()).toList(),
},
headers: getAuthorizationHeader(),
headers: _buildHeaders(idempotencyKey: idempotencyKey),
);
if (response.data['success'] == false) {
@@ -209,6 +220,7 @@ class OrderRemoteDataProvider {
required String reason,
String type = "ITEM", // TYPE: ALL, ITEM
required List<OrderItemDto> orderItems,
String? idempotencyKey,
}) async {
try {
final response = await _apiClient.post(
@@ -223,7 +235,7 @@ class OrderRemoteDataProvider {
)
.toList(),
},
headers: getAuthorizationHeader(),
headers: _buildHeaders(idempotencyKey: idempotencyKey),
);
if (response.data['success'] == false) {
@@ -238,14 +250,15 @@ class OrderRemoteDataProvider {
}
Future<DC<OrderFailure, PaymentDto>> createSplitBill(
PaymentSplitBillRequestDto request,
) async {
PaymentSplitBillRequestDto request, {
String? idempotencyKey,
}) async {
log(request.toRequest().toString());
try {
final response = await _apiClient.post(
"${ApiPath.orders}/split-bill",
data: request.toRequest(),
headers: getAuthorizationHeader(),
headers: _buildHeaders(idempotencyKey: idempotencyKey),
);
if (response.data['success'] == false) {
@@ -267,12 +280,13 @@ class OrderRemoteDataProvider {
required String id,
required String reason,
required int refundAmount,
String? idempotencyKey,
}) async {
try {
final response = await _apiClient.post(
'${ApiPath.orders}/$id/refund',
data: {'refund_amount': refundAmount, 'reason': reason},
headers: getAuthorizationHeader(),
headers: _buildHeaders(idempotencyKey: idempotencyKey),
);
if (response.data['success'] == false) {
@@ -110,6 +110,7 @@ class OrderRepository implements IOrderRepository {
Future<Either<OrderFailure, Order>> addItemOrder({
required String id,
required List<AddItemOrderRequest> request,
String? idempotencyKey,
}) async {
try {
final result = await _dataProvider.addItemOrder(
@@ -117,6 +118,7 @@ class OrderRepository implements IOrderRepository {
request: request
.map((e) => AddItemOrderRequestDto.fromDomain(e))
.toList(),
idempotencyKey: idempotencyKey,
);
if (result.hasError) {
@@ -134,10 +136,12 @@ class OrderRepository implements IOrderRepository {
@override
Future<Either<OrderFailure, Payment>> createPayment({
required PaymentRequest request,
String? idempotencyKey,
}) async {
try {
final result = await _dataProvider.storePayment(
PaymentRequestDto.fromDomain(request),
idempotencyKey: idempotencyKey,
);
if (result.hasError) {
@@ -158,6 +162,7 @@ class OrderRepository implements IOrderRepository {
required String reason,
String type = "ITEM",
required List<OrderItem> orderItems,
String? idempotencyKey,
}) async {
try {
final result = await _dataProvider.voidOrder(
@@ -165,6 +170,7 @@ class OrderRepository implements IOrderRepository {
reason: reason,
type: type,
orderItems: orderItems.map((e) => OrderItemDto.fromDomain(e)).toList(),
idempotencyKey: idempotencyKey,
);
if (result.hasError) {
@@ -180,11 +186,13 @@ class OrderRepository implements IOrderRepository {
@override
Future<Either<OrderFailure, Payment>> createSplitBill(
PaymentSplitBillRequest request,
) async {
PaymentSplitBillRequest request, {
String? idempotencyKey,
}) async {
try {
final result = await _dataProvider.createSplitBill(
PaymentSplitBillRequestDto.fromDomain(request),
idempotencyKey: idempotencyKey,
);
if (result.hasError) {
@@ -204,12 +212,14 @@ class OrderRepository implements IOrderRepository {
required String id,
required String reason,
required int refundAmount,
String? idempotencyKey,
}) async {
try {
final result = await _dataProvider.refundPayment(
id: id,
reason: reason,
refundAmount: refundAmount,
idempotencyKey: idempotencyKey,
);
if (result.hasError) {
return left(result.error!);