apskel-pos-flutter/lib/data/datasources/order_remote_datasource.dart
2025-08-07 12:34:57 +07:00

591 lines
19 KiB
Dart

import 'dart:convert';
import 'dart:developer';
import 'package:dartz/dartz.dart';
import 'package:dio/dio.dart';
import 'package:enaklo_pos/core/constants/variables.dart';
import 'package:enaklo_pos/core/network/dio_client.dart';
import 'package:enaklo_pos/data/datasources/auth_local_datasource.dart';
import 'package:enaklo_pos/data/models/request/payment_request.dart';
import 'package:enaklo_pos/data/models/response/order_response_model.dart';
import 'package:enaklo_pos/data/models/response/payment_method_response_model.dart';
import 'package:enaklo_pos/data/models/response/payment_methods_response_model.dart';
import 'package:enaklo_pos/data/models/response/payment_response_model.dart';
import 'package:enaklo_pos/data/models/response/summary_response_model.dart';
import 'package:enaklo_pos/presentation/home/models/order_model.dart';
import 'package:enaklo_pos/presentation/home/models/order_request.dart';
import 'package:http/http.dart' as http;
import 'package:intl/intl.dart';
class OrderRemoteDatasource {
final Dio dio = DioClient.instance;
//save order to remote server
Future<bool> saveOrder(OrderModel orderModel) async {
final authData = await AuthLocalDataSource().getAuthData();
print("🌐 API CALL: saveOrder");
print("📡 URL: ${Variables.baseUrl}/api/save-order");
print("🔑 Token: ${authData.token?.substring(0, 20)}...");
try {
final response = await http.post(
Uri.parse('${Variables.baseUrl}/api/save-order'),
body: orderModel.toJson(),
headers: {
'Authorization': 'Bearer ${authData.token}',
'Accept': 'application/json',
'Content-Type': 'application/json',
},
);
print("📥 HTTP Status Code: ${response.statusCode}");
print("📥 Response Body: ${response.body}");
print("📥 Response Headers: ${response.headers}");
if (response.statusCode == 200) {
print("✅ API call successful - Order saved to server");
return true;
} else {
print("❌ API call failed - Status: ${response.statusCode}");
print("❌ Error Response: ${response.body}");
return false;
}
} catch (e) {
print("💥 API call error: $e");
return false;
}
}
Future<Either<String, OrderResponseModel>> getOrderByRangeDate(
String stratDate,
String endDate,
) async {
try {
final authData = await AuthLocalDataSource().getAuthData();
final response = await http.get(
Uri.parse(
'${Variables.baseUrl}/api/orders?start_date=$stratDate&end_date=$endDate'),
headers: {
'Authorization': 'Bearer ${authData.token}',
'Accept': 'application/json',
'Content-Type': 'application/json',
},
);
print("📥 HTTP Status Code: ${response.statusCode}");
print("📥 Response Body: ${response.body}");
print("📥 Response Headers: ${response.headers}");
if (response.statusCode == 200) {
print("✅ getOrderByRangeDate API call successful");
return Right(OrderResponseModel.fromJson(response.body));
} else {
print(
"❌ getOrderByRangeDate API call failed - Status: ${response.statusCode}");
print("❌ Error Response: ${response.body}");
return const Left("Failed Load Data");
}
} catch (e) {
print("💥 getOrderByRangeDate API call error: $e");
return Left("Failed: $e");
}
}
Future<Either<String, SummaryResponseModel>> getSummaryByRangeDate(
String stratDate,
String endDate,
) async {
try {
final authData = await AuthLocalDataSource().getAuthData();
final response = await http.get(
Uri.parse(
'${Variables.baseUrl}/api/summary?start_date=$stratDate&end_date=$endDate'),
headers: {
'Authorization': 'Bearer ${authData.token}',
'Accept': 'application/json',
'Content-Type': 'application/json',
},
);
print("📡 URL: ${response.request!.url}");
print("📥 HTTP Status Code: ${response.statusCode}");
print("📥 Response Body: ${response.body}");
print("📥 Response Headers: ${response.headers}");
if (response.statusCode == 200) {
print("✅ getSummaryByRangeDate API call successful");
return Right(SummaryResponseModel.fromJson(response.body));
} else {
print(
"❌ getSummaryByRangeDate API call failed - Status: ${response.statusCode}");
print("❌ Error Response: ${response.body}");
return const Left("Failed Load Data");
}
} catch (e) {
print("💥 getSummaryByRangeDate API call error: $e");
return Left("Failed: $e");
}
}
Future<Either<String, PaymentMethodResponseModel>>
getPaymentMethodByRangeDate(
String startDate,
String endDate,
) async {
try {
final authData = await AuthLocalDataSource().getAuthData();
final response = await http.get(
Uri.parse(
'${Variables.baseUrl}/api/order-paymentmethod?start_date=$startDate&end_date=$endDate'),
headers: {
'Authorization': 'Bearer ${authData.token}',
'Accept': 'application/json',
'Content-Type': 'application/json',
},
);
print("📥 Payment Method HTTP Status Code: ${response.statusCode}");
print("📥 Payment Method Response Body: ${response.body}");
print("📥 Payment Method Response Headers: ${response.headers}");
if (response.statusCode == 200) {
print("✅ getPaymentMethodByRangeDate API call successful");
return Right(PaymentMethodResponseModel.fromJson(response.body));
} else {
print(
"❌ getPaymentMethodByRangeDate API call failed - Status: ${response.statusCode}");
print("❌ Error Response: ${response.body}");
return const Left("Failed Load Payment Method Data");
}
} catch (e) {
print("💥 getPaymentMethodByRangeDate API call error: $e");
return Left("Failed: $e");
}
}
Future<Either<String, bool>> addOrderItems(
int orderId,
List<Map<String, dynamic>> orderItems,
) async {
try {
final authData = await AuthLocalDataSource().getAuthData();
final response = await http.post(
Uri.parse('${Variables.baseUrl}/api/orders/add-items'),
headers: {
'Authorization': 'Bearer ${authData.token}',
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: jsonEncode({
'order_id': orderId,
'order_items': orderItems,
}),
);
print("📥 Add Order Items HTTP Status Code: ${response.statusCode}");
print("📥 Add Order Items Response Body: ${response.body}");
print("📥 Add Order Items Response Headers: ${response.headers}");
if (response.statusCode == 200) {
print("✅ addOrderItems API call successful");
return const Right(true);
} else {
print(
"❌ addOrderItems API call failed - Status: ${response.statusCode}");
print("❌ Error Response: ${response.body}");
return Left("Failed to add order items: ${response.body}");
}
} catch (e) {
print("💥 addOrderItems API call error: $e");
return Left("Failed: $e");
}
}
// New Api
Future<Either<String, OrderDetailResponseModel>> createOrder(
OrderRequestModel orderModel,
) async {
final authData = await AuthLocalDataSource().getAuthData();
final url = '${Variables.baseUrl}/api/v1/orders';
try {
final response = await dio.post(
url,
data: orderModel.toMap(),
options: Options(
headers: {
'Authorization': 'Bearer ${authData.token}',
'Accept': 'application/json',
'Content-Type': 'application/json',
},
),
);
if (response.statusCode == 200) {
return Right(OrderDetailResponseModel.fromMap(response.data));
} else {
return const Left('Gagal membuat pesanan');
}
} on DioException catch (e) {
final errorMessage =
e.response?.data['message'] ?? 'Terjadi kesalahan, coba lagi nanti.';
log("💥 Dio error: ${e.message}");
log("💥 Dio response: ${e.response?.data}");
return Left(errorMessage);
} catch (e) {
log("💥 Unexpected error: $e");
return const Left('Terjadi kesalahan tak terduga');
}
}
Future<Either<String, PaymentSuccessResponseModel>> createPayment(
PaymentRequestModel orderModel) async {
final authData = await AuthLocalDataSource().getAuthData();
final url = '${Variables.baseUrl}/api/v1/payments';
try {
final response = await dio.post(
url,
data: orderModel.toMap(),
options: Options(
headers: {
'Authorization': 'Bearer ${authData.token}',
'Accept': 'application/json',
'Content-Type': 'application/json',
},
),
);
if (response.statusCode == 200) {
return Right(PaymentSuccessResponseModel.fromMap(response.data));
} else {
return const Left('Gagal membuat pembayaran');
}
} on DioException catch (e) {
final errorMessage =
e.response?.data['message'] ?? 'Terjadi kesalahan, coba lagi nanti.';
log("💥 Dio error: ${e.message}");
log("💥 Dio response: ${e.response?.data}");
return Left(errorMessage);
} catch (e) {
log("💥 Unexpected error: $e");
return const Left('Terjadi kesalahan tak terduga');
}
}
Future<Either<String, OrderResponseModel>> getOrder({
int page = 1,
int limit = Variables.defaultLimit,
String status = 'completed',
required DateTime dateFrom,
required DateTime dateTo,
String? search,
}) async {
try {
final authData = await AuthLocalDataSource().getAuthData();
Map<String, dynamic> params = {
'page': page,
'limit': limit,
'status': status,
'date_from': DateFormat('dd-MM-yyyy').format(dateFrom),
'date_to': DateFormat('dd-MM-yyyy').format(dateTo),
};
if (search != null && search.isNotEmpty) {
params['search'] = search;
}
final response = await dio.get(
'${Variables.baseUrl}/api/v1/orders',
queryParameters: params,
options: Options(
headers: {
'Authorization': 'Bearer ${authData.token}',
'Accept': 'application/json',
'Content-Type': 'application/json',
},
),
);
if (response.statusCode == 200) {
return Right(OrderResponseModel.fromMap(response.data));
} else {
log("❌ getOrderByRangeDate API call failed - Status: ${response.statusCode}");
return const Left("Failed Load Data");
}
} on DioException catch (e) {
final errorMessage = 'Something went wrong';
log("💥 Dio error: ${e.message}");
log("💥 Dio response: ${e.response?.data}");
return Left(errorMessage);
} catch (e) {
log("💥 Unexpected error: $e");
return Left("Unexpected Error: $e");
}
}
Future<Either<String, OrderDetailResponseModel>> getOrderById(
{required String orderId}) async {
try {
final authData = await AuthLocalDataSource().getAuthData();
final response = await dio.get(
'${Variables.baseUrl}/api/v1/orders/$orderId',
options: Options(
headers: {
'Authorization': 'Bearer ${authData.token}',
'Accept': 'application/json',
'Content-Type': 'application/json',
},
),
);
if (response.statusCode == 200) {
return Right(OrderDetailResponseModel.fromMap(response.data));
} else {
log("❌ OrderDetailResponseModel API call failed - Status: ${response.statusCode}");
return const Left("Failed Load Data");
}
} on DioException catch (e) {
final errorMessage = 'Something went wrong';
log("💥 Dio error: ${e.message}");
log("💥 Dio response: ${e.response?.data}");
return Left(errorMessage);
} catch (e) {
log("💥 Unexpected error: $e");
return Left("Unexpected Error: $e");
}
}
Future<Either<String, OrderDetailResponseModel>> createOrderWithPayment(
OrderRequestModel orderModel,
PaymentMethod payment,
) async {
final authData = await AuthLocalDataSource().getAuthData();
final url = '${Variables.baseUrl}/api/v1/orders';
try {
final response = await dio.post(
url,
data: orderModel.toMap(),
options: Options(
headers: {
'Authorization': 'Bearer ${authData.token}',
'Accept': 'application/json',
'Content-Type': 'application/json',
},
),
);
if (response.statusCode == 200) {
final data = OrderDetailResponseModel.fromMap(response.data);
final orderData = data.data;
final paymentRequest = PaymentRequestModel(
orderId: orderData?.id,
amount: orderData?.totalAmount,
paymentMethodId: payment.id,
splitDescription: '',
splitNumber: 1,
splitTotal: 1,
paymentOrderItems: orderData?.orderItems
?.map((item) => PaymentOrderItemModel(
amount: item.totalPrice,
orderItemId: item.id,
))
.toList(),
);
createPayment(paymentRequest);
return Right(data);
} else {
return const Left('Gagal membuat pesanan');
}
} on DioException catch (e) {
final errorMessage =
e.response?.data['message'] ?? 'Terjadi kesalahan, coba lagi nanti.';
log("💥 Dio error: ${e.message}");
log("💥 Dio response: ${e.response?.data}");
return Left(errorMessage);
} catch (e) {
log("💥 Unexpected error: $e");
return const Left('Terjadi kesalahan tak terduga');
}
}
Future<Either<String, OrderDetailResponseModel>> addToOrder({
required String orderId,
required List<OrderItemRequest> orderItems,
}) async {
final authData = await AuthLocalDataSource().getAuthData();
final url = '${Variables.baseUrl}/api/v1/orders/$orderId/add-items';
try {
final response = await dio.post(
url,
data: {
"order_items": orderItems.map((item) => item.toMap()).toList(),
'notes': '',
},
options: Options(
headers: {
'Authorization': 'Bearer ${authData.token}',
'Accept': 'application/json',
'Content-Type': 'application/json',
},
),
);
if (response.statusCode == 200) {
final data = OrderDetailResponseModel.fromMap(response.data);
return Right(data);
} else {
return const Left('Gagal menambahkan pesanan pesanan');
}
} on DioException catch (e) {
final errorMessage =
e.response?.data['message'] ?? 'Terjadi kesalahan, coba lagi nanti.';
log("💥 Dio error: ${e.message}");
log("💥 Dio response: ${e.response?.data}");
return Left(errorMessage);
} catch (e) {
log("💥 Unexpected error: $e");
return const Left('Terjadi kesalahan tak terduga');
}
}
Future<Either<String, bool>> refund({
required String orderId,
required String reason,
required List<OrderItem> orderItems,
}) async {
final authData = await AuthLocalDataSource().getAuthData();
final url = '${Variables.baseUrl}/api/v1/orders/$orderId/refund';
final int refundAmount = orderItems.fold(
0,
(sum, item) => sum + ((item.unitPrice ?? 0) * (item.quantity ?? 0)),
);
try {
final response = await dio.post(
url,
data: {
'refund_amount': refundAmount,
"order_items": orderItems
.map((item) => {
'order_item_id': item.id,
"refund_quantity": item.quantity,
"refund_amount": item.totalPrice,
"reason": ""
})
.toList(),
'reason': reason,
},
options: Options(
headers: {
'Authorization': 'Bearer ${authData.token}',
'Accept': 'application/json',
'Content-Type': 'application/json',
},
),
);
if (response.statusCode == 200) {
return Right(true);
} else {
return const Left('Gagal refund');
}
} on DioException catch (e) {
final errorMessage =
e.response?.data['message'] ?? 'Terjadi kesalahan, coba lagi nanti.';
log("💥 Dio error: ${e.message}");
log("💥 Dio response: ${e.response?.data}");
return Left(errorMessage);
} catch (e) {
log("💥 Unexpected error: $e");
return const Left('Terjadi kesalahan tak terduga');
}
}
Future<Either<String, bool>> voidOrder({
required String orderId,
required String reason,
String type = "ITEM", // TYPE: ALL, ITEM
required List<OrderItem> orderItems,
}) async {
final authData = await AuthLocalDataSource().getAuthData();
final url = '${Variables.baseUrl}/api/v1/orders/void';
try {
final response = await dio.post(
url,
data: {
'order_id': orderId,
'type': orderItems.isEmpty ? "ALL" : type,
'reason': reason,
"items": orderItems
.map((item) => {
'order_item_id': item.id,
"quantity": item.quantity,
})
.toList(),
},
options: Options(
headers: {
'Authorization': 'Bearer ${authData.token}',
'Accept': 'application/json',
'Content-Type': 'application/json',
},
),
);
if (response.statusCode == 200) {
return Right(true);
} else {
return const Left('Gagal refund');
}
} on DioException catch (e) {
final errorMessage =
e.response?.data['message'] ?? 'Terjadi kesalahan, coba lagi nanti.';
log("💥 Dio error: ${e.message}");
log("💥 Dio response: ${e.response?.data}");
return Left(errorMessage);
} catch (e) {
log("💥 Unexpected error: $e");
return const Left('Terjadi kesalahan tak terduga');
}
}
Future<Either<String, bool>> refundPayment({
required String orderId,
required String reason,
required int refundAmount,
}) async {
final authData = await AuthLocalDataSource().getAuthData();
final url = '${Variables.baseUrl}/api/v1/orders/$orderId/refund';
try {
final response = await dio.post(
url,
data: {
'refund_amount': refundAmount,
'reason': reason,
},
options: Options(
headers: {
'Authorization': 'Bearer ${authData.token}',
'Accept': 'application/json',
'Content-Type': 'application/json',
},
),
);
if (response.statusCode == 200) {
return Right(true);
} else {
return const Left('Gagal refund');
}
} on DioException catch (e) {
final errorMessage = 'Terjadi kesalahan coba lagi nanti';
log("💥 Dio error: ${e.message}");
log("💥 Dio response: ${e.response?.data}");
return Left(errorMessage);
} catch (e) {
log("💥 Unexpected error: $e");
return const Left('Terjadi kesalahan tak terduga');
}
}
}