Created
September 4, 2025 11:07
-
-
Save jafar260698/f9ed1b7c2beced34eba272086b280dea to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import 'dart:collection'; | |
| import 'dart:convert'; | |
| import 'dart:io'; | |
| import 'package:intl/intl.dart'; | |
| import 'package:path_provider/path_provider.dart'; | |
| import 'package:pos_system/utils/app_date_utils.dart'; | |
| import 'package:pos_system/utils/app_utils.dart'; | |
| import 'package:pos_system/utils/logger/write_log.dart'; | |
| import 'package:qr_flutter/qr_flutter.dart'; | |
| import 'package:shelf/shelf.dart'; | |
| import 'package:uuid/uuid.dart'; | |
| import 'core/services/locator.dart'; | |
| import 'data/models/front_office_model.dart'; | |
| import 'data/pos_data/fiscal_drive/fiscal_drive_receipt.dart'; | |
| import 'data/pos_data/receipt_item.dart'; | |
| import 'data/user_data.dart'; | |
| import 'domain/network/api_provider.dart'; | |
| import 'domain/persistance/db/virtual_cash_db.dart'; | |
| import 'package:drift/drift.dart' as drift; | |
| import 'dart:ui' as ui; | |
| class SendReceiptFrontOffice { | |
| SendReceiptFrontOffice._(); | |
| static final instance = SendReceiptFrontOffice._(); | |
| static Future<Response> sendReceipt(Request request) async { | |
| try { | |
| final body = await request.readAsString(); | |
| final saleData = FrontOfficeModel.fromJson(jsonDecode(body)); | |
| final apiProvider = locator<ApiProvider>(); | |
| final userData = locator<UserData>(); | |
| final VirtualCashDb virtualCashDb = locator<VirtualCashDb>(); | |
| bool existIntegrationID = await virtualCashDb.integrationIdExists(saleData.transactionId ?? ""); | |
| WriteLOG.writeLog("IntegrationID: ${saleData.transactionId}; $existIntegrationID;"); | |
| if (existIntegrationID) { | |
| var cheque = await virtualCashDb.getChequeByIntegrationId(saleData.transactionId ?? ""); | |
| var sendToBackend = await virtualCashDb.getSendToBackendStatus(cheque?.receiptId ?? ""); | |
| if(sendToBackend == 1) { | |
| var result = await apiProvider.sendSingleReceiptWithoutContext(cheque?.receiptId ?? ""); | |
| if (result.data != null) { | |
| var htmlData = await generateChequeHTMLByIntegration(result.data!); | |
| return Response.ok( | |
| jsonEncode({ | |
| 'success': true, | |
| 'reason': '', | |
| 'html': htmlData | |
| })); | |
| } else { | |
| return Response( | |
| 400, | |
| body: jsonEncode({ | |
| 'success': false, | |
| 'reason': 'Fiskal modul bilan yuborishda xatolik:', | |
| }), | |
| headers: {'Content-Type': 'application/json'}, | |
| ); | |
| } | |
| } else { | |
| var hasSmena = await userData.getSmenaStatus(); | |
| if (hasSmena ?? false) { | |
| try { | |
| Map<String, dynamic> paramsSaleReceipt = HashMap(); | |
| var currentTime = getCurrentDate(); | |
| var randomNum = AppUtils.getRandomNumber(); | |
| var fiscalId = await userData.getFiscalId(); | |
| var receiptList = []; | |
| for (var element in saleData.invoiceDataItems ?? []) { | |
| InvoiceDataItems invoiceDataItems = element; | |
| receiptList.add( | |
| { | |
| "Discount": invoiceDataItems.discount, | |
| "Name": invoiceDataItems.productName, | |
| "Barcode": invoiceDataItems.barcode ?? "", | |
| "PackageCode": invoiceDataItems.units.toString(), | |
| "SPIC": invoiceDataItems.classCode, | |
| "OwnerType": 2, | |
| "Amount": (invoiceDataItems.count ?? 0) * 1000, | |
| "Label": "", | |
| "Price": invoiceDataItems.price!.toInt() * | |
| invoiceDataItems.count! * 100, | |
| "Units": invoiceDataItems.units, | |
| "VAT": invoiceDataItems.vatPercent, | |
| "VATPercent": invoiceDataItems.vatPercent, | |
| "CommissionInfo": { | |
| "PINFL": invoiceDataItems.commissionPinfl ?? "", | |
| "TIN": invoiceDataItems.comissionTin ?? "" | |
| }, | |
| "Other": 0 | |
| } | |
| ); | |
| } | |
| paramsSaleReceipt = { | |
| "method": "Api.SendSaleReceipt", | |
| "id": randomNum, | |
| "params": { | |
| "FactoryID": fiscalId, | |
| "Receipt": { | |
| "ReceivedCash": saleData.paymentTypeId == 1 ? (saleData | |
| .totalSum! * 100) : 0, | |
| "Time": currentTime, | |
| "Items": receiptList, | |
| "ReceivedCard": saleData.paymentTypeId == 2 ? (saleData | |
| .totalSum! * 100) : 0, | |
| "Location": { | |
| "Latitude": await userData.getLatitude(), | |
| "Longitude": await userData.getLongitude(), | |
| }, | |
| } | |
| }, | |
| "jsonrpc": "2.0" | |
| }; | |
| var response = await apiProvider | |
| .sendReceiptFiscalDriveWithoutContext(paramsSaleReceipt); | |
| if (response != null && response.result != null) { | |
| return sendReceiptsBackend(response.result!, saleData); | |
| } else { | |
| return Response( | |
| 400, | |
| body: jsonEncode({ | |
| 'success': false, | |
| 'reason': 'Fiskal modul bilan yuborishda xatolik: ${response | |
| .error?.message}', // Custom error message | |
| }), | |
| headers: {'Content-Type': 'application/json'}, | |
| ); | |
| } | |
| } catch (e) { | |
| WriteLOG.writeLog(e.toString()); | |
| return Response( | |
| 400, // HTTP status code for "Bad Request" | |
| body: jsonEncode({ | |
| 'success': false, | |
| 'reason': 'Server bilan xatolik: $e', | |
| }), | |
| headers: {'Content-Type': 'application/json'}, | |
| ); | |
| } | |
| } else { | |
| return Response( | |
| 400, // HTTP status code for "Bad Request" | |
| body: jsonEncode({ | |
| 'success': false, | |
| 'reason': 'Virtual Kassada Smena ochilmagan:', | |
| // Custom error message | |
| }), | |
| headers: {'Content-Type': 'application/json'}, | |
| ); | |
| } | |
| } | |
| } else { | |
| var hasSmena = await userData.getSmenaStatus(); | |
| if (hasSmena ?? false) { | |
| try { | |
| Map<String, dynamic> paramsSaleReceipt = HashMap(); | |
| var currentTime = getCurrentDate(); | |
| var randomNum = AppUtils.getRandomNumber(); | |
| var fiscalId = await userData.getFiscalId(); | |
| var receiptList = []; | |
| for (var element in saleData.invoiceDataItems ?? []) { | |
| InvoiceDataItems invoiceDataItems = element; | |
| receiptList.add( | |
| { | |
| "Discount": invoiceDataItems.discount, | |
| "Name": invoiceDataItems.productName, | |
| "Barcode": invoiceDataItems.barcode ?? "", | |
| "PackageCode": invoiceDataItems.units.toString(), | |
| "SPIC": invoiceDataItems.classCode, | |
| "OwnerType": 2, | |
| "Amount": (invoiceDataItems.count ?? 0) * 1000, | |
| "Label": "", | |
| "Price": invoiceDataItems.price!.toInt() * | |
| invoiceDataItems.count! * 100, | |
| "Units": invoiceDataItems.units, | |
| "VAT": invoiceDataItems.vatPercent, | |
| "VATPercent": invoiceDataItems.vatPercent, | |
| "CommissionInfo": { | |
| "PINFL": invoiceDataItems.commissionPinfl ?? "", | |
| "TIN": invoiceDataItems.comissionTin ?? "" | |
| }, | |
| "Other": 0 | |
| } | |
| ); | |
| } | |
| paramsSaleReceipt = { | |
| "method": "Api.SendSaleReceipt", | |
| "id": randomNum, | |
| "params": { | |
| "FactoryID": fiscalId, | |
| "Receipt": { | |
| "ReceivedCash": saleData.paymentTypeId == 1 ? (saleData | |
| .totalSum! * 100) : 0, | |
| "Time": currentTime, | |
| "Items": receiptList, | |
| "ReceivedCard": saleData.paymentTypeId == 2 ? (saleData | |
| .totalSum! * 100) : 0, | |
| "Location": { | |
| "Latitude": await userData.getLatitude(), | |
| "Longitude": await userData.getLongitude(), | |
| }, | |
| } | |
| }, | |
| "jsonrpc": "2.0" | |
| }; | |
| var response = await apiProvider | |
| .sendReceiptFiscalDriveWithoutContext(paramsSaleReceipt); | |
| if (response != null && response.result != null) { | |
| return sendReceiptsBackend(response.result!, saleData); | |
| } else { | |
| return Response( | |
| 400, | |
| body: jsonEncode({ | |
| 'success': false, | |
| 'reason': 'Fiskal modul bilan yuborishda xatolik: ${response | |
| .error?.message}', // Custom error message | |
| }), | |
| headers: {'Content-Type': 'application/json'}, | |
| ); | |
| } | |
| } catch (e) { | |
| WriteLOG.writeLog(e.toString()); | |
| return Response( | |
| 400, // HTTP status code for "Bad Request" | |
| body: jsonEncode({ | |
| 'success': false, | |
| 'reason': 'Fiskal modul bilan yuborishda xatolik: $e', | |
| // Custom error message | |
| }), | |
| headers: {'Content-Type': 'application/json'}, | |
| ); | |
| } | |
| } else { | |
| return Response( | |
| 400, // HTTP status code for "Bad Request" | |
| body: jsonEncode({ | |
| 'success': false, | |
| 'reason': 'Virtual Kassada Smena ochilmagan:', | |
| // Custom error message | |
| }), | |
| headers: {'Content-Type': 'application/json'}, | |
| ); | |
| } | |
| } | |
| } catch(error) { | |
| WriteLOG.writeLog(error.toString()); | |
| return Response( | |
| 400, | |
| body: jsonEncode({ | |
| 'success': false, | |
| 'reason': 'Xatolik: ${error}', | |
| }), | |
| headers: {'Content-Type': 'application/json'}, | |
| ); | |
| } | |
| } | |
| static Future<Response> sendReceiptsBackend( | |
| FiscalDriveReceiptResult fiscalDriveReceiptResult, | |
| FrontOfficeModel frontOfficeModel) async { | |
| try { | |
| var currentTime = getCurrentDate(); | |
| var receiptList = []; | |
| var ofdDateTime = getCustomDate(fiscalDriveReceiptResult.dateTime ?? ""); | |
| final VirtualCashDb virtualCashDb = locator<VirtualCashDb>(); | |
| final apiProvider = locator<ApiProvider>(); | |
| final userData = locator<UserData>(); | |
| var receiptId = const Uuid().v1(); | |
| var companyId = (await userData.getCompanyId()) ?? ""; | |
| var userId = (await userData.getUserId()) ?? ""; | |
| var smenaId = (await userData.getSmenaId()) ?? ""; | |
| var cashboxId = await userData.getCashboxId() ?? ""; | |
| for (var element in frontOfficeModel.invoiceDataItems!) { | |
| InvoiceDataItems invoiceDataItems = element; | |
| var receiptItemsId = const Uuid().v1(); | |
| receiptList.add( | |
| { | |
| "commission_pinfl": invoiceDataItems.commissionPinfl ?? "", | |
| "commission_tin": invoiceDataItems.comissionTin ?? "", | |
| "discount_sum": invoiceDataItems.discount, | |
| "discount_value": 0, | |
| "discount_type": "no_discount", | |
| "product_name": invoiceDataItems.productName, | |
| "product_barcode": invoiceDataItems.barcode! ?? "", | |
| "product_class_code": invoiceDataItems.classCode, | |
| "product_class_name": invoiceDataItems.className, | |
| "product_id": invoiceDataItems.productId.toString(), | |
| "product_mxik_code": invoiceDataItems.classCode, | |
| "receipt_item_id": receiptItemsId, | |
| "sale_count": invoiceDataItems.count, | |
| "sale_price": invoiceDataItems.price, | |
| "total_price": invoiceDataItems.totalPrice, | |
| "vat_percent": invoiceDataItems.vatPercent, | |
| "vat_sum": invoiceDataItems.vatSum, | |
| "product_package_code": invoiceDataItems.units.toString(), | |
| "owner_type": 2, | |
| "product_type": 2, | |
| } | |
| ); | |
| var salesProduct = SoldProductEntityCompanion( | |
| commissionPinfl: drift.Value(invoiceDataItems.commissionPinfl ?? ""), | |
| commissionTin: drift.Value(invoiceDataItems.comissionTin ?? ""), | |
| discountValue: const drift.Value.absentIfNull(0), | |
| discountSum: const drift.Value.absentIfNull(0), | |
| discountType: const drift.Value.absentIfNull("no_discount"), | |
| productName: drift.Value.absentIfNull(invoiceDataItems.productName), | |
| productBarcode: drift.Value.absentIfNull(invoiceDataItems.barcode), | |
| productClassCode: drift.Value.absentIfNull( | |
| invoiceDataItems.classCode), | |
| productClassName: drift.Value.absentIfNull( | |
| invoiceDataItems.className), | |
| productId: drift.Value.absentIfNull( | |
| invoiceDataItems.productId.toString()), | |
| productMxikCode: drift.Value.absentIfNull( | |
| invoiceDataItems.classCode), | |
| receiptItemId: drift.Value.absentIfNull(receiptItemsId), | |
| saleCount: drift.Value(invoiceDataItems.count?.toDouble()), | |
| salePrice: drift.Value(invoiceDataItems.price?.toDouble()), | |
| totalPrice: drift.Value(invoiceDataItems.totalPrice?.toDouble()), | |
| vatPercent: drift.Value(invoiceDataItems.vatPercent), | |
| vatSum: const drift.Value(0), | |
| chequeId: drift.Value(receiptId), | |
| hasMarking: const drift.Value(0), | |
| markingCode: const drift.Value(""), | |
| ownerType: const drift.Value(2), | |
| productType: const drift.Value(2), | |
| packageCode: drift.Value.absentIfNull(invoiceDataItems.units.toString()), | |
| ); | |
| virtualCashDb.insertSoldProduct(salesProduct); | |
| } | |
| var paymentTypeList = []; | |
| var paymentDateId = const Uuid().v1(); | |
| // 1 - Naqd, 2 Plastik | |
| var paymentTypeID = ""; | |
| if (frontOfficeModel.paymentTypeId == 1) { | |
| paymentTypeID = "e0b691e1-3f78-4bf3-816f-e50b2f9e8e5f"; | |
| } else if (frontOfficeModel.paymentTypeId == 2) { | |
| paymentTypeID = "f4f47104-662f-4e20-92cf-56cbf71d206d"; | |
| } | |
| paymentTypeList.add({ | |
| "amount": frontOfficeModel.totalSum, | |
| "pay_sum": frontOfficeModel.totalPaySum, | |
| "payment_data_id": paymentDateId, | |
| "payment_type_id": paymentTypeID, | |
| "provider_id": "", | |
| }); | |
| var paymentDate = PaymentDateEntityCompanion( | |
| paySum: drift.Value(frontOfficeModel.totalPaySum!.toDouble()), | |
| paymentDataId: drift.Value(paymentDateId), | |
| paymentTypeId: drift.Value(paymentTypeID), | |
| chequeId: drift.Value(receiptId) | |
| ); | |
| virtualCashDb.insertPaymentDate(paymentDate); | |
| // | |
| var totalReceivedCash = frontOfficeModel.paymentTypeId == 1 | |
| ? frontOfficeModel.totalPaySum! | |
| : 0.0; | |
| var totalReceivedCard = frontOfficeModel.paymentTypeId != 1 | |
| ? frontOfficeModel.totalPaySum! | |
| : 0.0; | |
| var list = [ | |
| { | |
| "cashback": 0, | |
| "cashbox_id": cashboxId, | |
| "company_id": companyId, | |
| "created_date": currentTime, | |
| "total_discount_sum": 0, | |
| "ofd_date_time": ofdDateTime, | |
| "ofd_fiscal_sign": fiscalDriveReceiptResult.fiscalSign, | |
| "ofd_qr_code_url": fiscalDriveReceiptResult.qRCodeURL, | |
| "ofd_receipt_sequence_number": int.parse(fiscalDriveReceiptResult.receiptSeq ?? "0"), | |
| "ofd_terminal_id": fiscalDriveReceiptResult.terminalID, | |
| "payment_data": paymentTypeList, | |
| "receipt_id": receiptId, | |
| "receipt_items": receiptList, | |
| "receipt_type": "sale", | |
| "sale_day_id": smenaId, | |
| "send_ofd_status": true, | |
| "total_pay": frontOfficeModel.totalPaySum!, | |
| "total_sum": frontOfficeModel.totalSum!, | |
| "total_vat_sum": frontOfficeModel.vatSum, | |
| "user_id": userId, | |
| "total_received_cash": totalReceivedCash, | |
| "total_received_card": totalReceivedCard, | |
| "app_version": await AppUtils.initVersion() | |
| } | |
| ]; | |
| var chequeItem = ChequeEntityCompanion( | |
| cashback: const drift.Value(0), | |
| cashboxId: drift.Value(cashboxId), | |
| companyId: drift.Value(companyId), | |
| createdDate: drift.Value(currentTime), | |
| discountSum: const drift.Value(0), | |
| ofdDateTime: drift.Value(ofdDateTime), | |
| ofdFiscalSign: drift.Value(fiscalDriveReceiptResult.fiscalSign), | |
| ofdQrCodeUrl: drift.Value(fiscalDriveReceiptResult.qRCodeURL), | |
| ofdReceiptSequenceNumber: drift.Value(fiscalDriveReceiptResult.receiptSeq), | |
| ofdTerminalId: drift.Value(fiscalDriveReceiptResult.terminalID), | |
| receiptId: drift.Value(receiptId), | |
| receiptType: const drift.Value("sale"), | |
| saleDayId: drift.Value(smenaId), | |
| sendOfdStatus: const drift.Value(1), | |
| totalPay: drift.Value(frontOfficeModel.totalPaySum?.toDouble()), | |
| totalSum: drift.Value(frontOfficeModel.totalSum?.toDouble() ?? 0), | |
| totalVatSum: drift.Value(frontOfficeModel.vatSum?.toDouble()), | |
| userId: drift.Value(userId), | |
| senToBackend: const drift.Value(0), | |
| totalReceivedCard: drift.Value(totalReceivedCard.toDouble()), | |
| totalReceivedCash: drift.Value(totalReceivedCash.toDouble()), | |
| isIntegration: const drift.Value(1), | |
| integrationId: drift.Value(frontOfficeModel.transactionId), | |
| ); | |
| await virtualCashDb.insertChequeFrontOffice(chequeItem, frontOfficeModel.transactionId ?? ""); | |
| var result = await apiProvider.sendReceiptWithoutContext(list); | |
| if (result.data != null) { | |
| virtualCashDb.updateSingleRow(receiptId, 1); | |
| } | |
| var htmlData = await generateChequeHTML(fiscalDriveReceiptResult, frontOfficeModel); | |
| return Response.ok( | |
| jsonEncode({ | |
| 'success': true, | |
| 'reason': '', | |
| 'html': htmlData | |
| }), | |
| headers: {'Content-Type': 'application/json'}, | |
| ); | |
| } catch (e) { | |
| WriteLOG.writeLog("Debug error2 $e"); | |
| return Response( | |
| 400, | |
| body: jsonEncode({ | |
| 'success': false, | |
| 'reason': 'Serverga yuborishda xatolik: $e', // Custom error message | |
| }), | |
| headers: {'Content-Type': 'application/json'}, | |
| ); | |
| } | |
| } | |
| static Future<String> generateChequeHTML( | |
| FiscalDriveReceiptResult fiscalDriveReceiptResult, | |
| FrontOfficeModel frontOfficeModel) async { | |
| try { | |
| final UserData userData = locator<UserData>(); | |
| var companyStir = (await userData.getCompanyTin()) ?? ""; | |
| var companyAddress = (await userData.getCashboxAddress()) ?? ""; | |
| var cashier = (await userData.getUserName() ?? ""); | |
| var cashboxId = (await userData.getCashboxId()); | |
| var versionApp = await AppUtils.initVersion(); | |
| // Format Money | |
| String formatMoney(double amount) { | |
| final formatter = NumberFormat.currency(symbol: '', decimalDigits: 2); | |
| return formatter.format(amount); | |
| } | |
| var invoicesDataItems = frontOfficeModel.invoiceDataItems; | |
| // Prepare items in HTML | |
| String chequeItems = ""; | |
| for (var item in invoicesDataItems!) { | |
| chequeItems += """ | |
| <div style='font-size: 10px'>${item.productName} - ${item.units}</div> | |
| <div style='font-size: 10px;text-align: right;'>${formatMoney( | |
| item.price!.toDouble())} x ${formatMoney( | |
| item.count!.toDouble())} = ${formatMoney( | |
| item.totalPrice!.toDouble())}</div> | |
| <div style='font-size: 10px;'>QQS - ${item.vatPercent}%</div> | |
| <div style='font-size: 10px;'>MXIK: ${item.classCode}</div> | |
| <div style='font-size: 10px;'>Shtrix kod: ${item.barcode}</div> | |
| """; | |
| } | |
| // Generate QR code | |
| String qrCodeImage = await generateBase64QRCode(fiscalDriveReceiptResult.qRCodeURL!); | |
| // HTML content | |
| String htmlContent = """ | |
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <style> | |
| @page { | |
| margin: 0; | |
| } | |
| body { font-family: Arial, sans-serif; margin:0; padding: 0; } | |
| .header { text-align: center; font-size: 12px; } | |
| .row { font-size: 11px; display: flex; justify-content: space-between; } | |
| .divider { border-top: 1px solid black; margin: 10px 0; } | |
| .qr-code { | |
| padding: 10px; | |
| } | |
| img { | |
| width: 150px; /* Adjust size as needed */ | |
| height: 150px; | |
| object-fit: contain; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="header"> | |
| <h4 style="text-align:center">O’zbekiston Respublikasi Vazirlar Mahkamasi huzuridagi Soliq-Servis DUK</h4> | |
| <p>$companyAddress</p> | |
| </div> | |
| <hr class="divider"/> | |
| <div class="row"> | |
| <span>STIR:</span> | |
| <span>$companyStir</span> | |
| </div> | |
| <div class="row"> | |
| <span>Sana:</span> | |
| <span>${getCustomDate(fiscalDriveReceiptResult.dateTime!)}</span> | |
| </div> | |
| <div class="row"> | |
| <span>Chek raqami:</span> | |
| <span>${fiscalDriveReceiptResult.receiptSeq}</span> | |
| </div> | |
| <div class="row"> | |
| <span>Kassir:</span><span>$cashier</span> | |
| </div> | |
| <div class="divider"></div> | |
| <!-- Invoice Items --> | |
| $chequeItems | |
| <div class="divider"></div> | |
| <div class="row" style="font-size: 13px; font-weight: bold;"> | |
| <span>Jami:</span> | |
| <span>${formatMoney(frontOfficeModel.totalSum!.toDouble())}</span> | |
| </div> | |
| <div class="row"> | |
| <span>QQS:</span> | |
| <span>${formatMoney(frontOfficeModel.vatSum!.toDouble())}</span> | |
| </div> | |
| <div class="row" style="font-size: 12px; font-weight: bold;"> | |
| <span>To'lov:</span> | |
| <span>${formatMoney(frontOfficeModel.totalPaySum!.toDouble())}</span> | |
| </div> | |
| <hr class="divider"/> | |
| <div class="row"> | |
| <span>Naqd:</span> | |
| <span>${frontOfficeModel.paymentTypeId == 1 ? formatMoney(frontOfficeModel.totalSum!.toDouble()) : 0.0}</span> | |
| </div> | |
| <div class="row"> | |
| <span>Karta orqali:</span> | |
| <span>${frontOfficeModel.paymentTypeId == 2 ? formatMoney(frontOfficeModel.totalSum!.toDouble()) : 0.0}</span> | |
| </div> | |
| <div class="row"> | |
| <span>Qaytim:</span> | |
| <span>${formatMoney(0.0)}</span> | |
| </div> | |
| <div class="divider" style="border-top: 2px dashed black;"></div> | |
| <div style="text-align: center; font-weight: bold;"> | |
| Fiskal ma'lumotlar | |
| </div> | |
| <div class="row" style="font-size: 11px; font-weight: bold;"> | |
| <span>Virtual Kassa $versionApp version</span><span></span> | |
| </div> | |
| <div class="row" style="font-size: 11px;"> | |
| <span>$cashboxId</span><span></span> | |
| </div> | |
| <div class="row" style="font-size: 11px; font-weight: bold;"> | |
| <span>FM raqami:</span><span>${fiscalDriveReceiptResult.terminalID}</span> | |
| </div> | |
| <div class="row" style="font-size: 11px; font-weight: bold;"> | |
| <span>Chek raqami:</span><span>${fiscalDriveReceiptResult.receiptSeq}</span> | |
| </div> | |
| <div class="row" style="font-size: 11px; font-weight: bold;"> | |
| <span>Fiskal belgi:</span><span>${fiscalDriveReceiptResult.fiscalSign}</span> | |
| </div> | |
| <div class="qr-code"> | |
| <img src='data:image/png;base64,$qrCodeImage' alt='QR Code'> | |
| </div> | |
| </body> | |
| </html> | |
| """; | |
| // Saving the HTML content to a file | |
| final directory = await getApplicationDocumentsDirectory(); | |
| final filePath = '${directory.path}/receipt.html'; | |
| final file = File(filePath); | |
| await file.writeAsString(htmlContent); | |
| return htmlContent; | |
| } catch (e) { | |
| WriteLOG.writeLog(e.toString()); | |
| return ""; | |
| } | |
| } | |
| static Future<String> generateChequeHTMLByIntegration(ReceiptData receiptData) async { | |
| try { | |
| final UserData userData = locator<UserData>(); | |
| var companyStir = (await userData.getCompanyTin()) ?? ""; | |
| var companyAddress = (await userData.getCashboxAddress()) ?? ""; | |
| var cashier = (await userData.getUserName() ?? ""); | |
| var cashboxId = (await userData.getCashboxId()); | |
| var versionApp = await AppUtils.initVersion(); | |
| var totalCash = 0.0; | |
| var totalCard = 0.0; | |
| receiptData.paymentData?.forEach((element) { | |
| if(element.paymentTypeId == "e0b691e1-3f78-4bf3-816f-e50b2f9e8e5f"){ | |
| totalCash = (element.paySum ?? 0).toDouble(); | |
| } | |
| if(element.paymentTypeId == "f4f47104-662f-4e20-92cf-56cbf71d206d"){ | |
| totalCard = (element.paySum ?? 0).toDouble(); | |
| } | |
| }); | |
| // Format Money | |
| String formatMoney(double amount) { | |
| final formatter = NumberFormat.currency(symbol: '', decimalDigits: 2); | |
| return formatter.format(amount); | |
| } | |
| var invoicesDataItems = receiptData.receiptItems; | |
| // Prepare items in HTML | |
| String chequeItems = ""; | |
| for (var item in invoicesDataItems!) { | |
| chequeItems += """ | |
| <div style='font-size: 10px'>${item.productName} - ${item.productMeasureType}</div> | |
| <div style='font-size: 10px;text-align: right;'>${formatMoney( | |
| item.productSalePrice!.toDouble())} x ${formatMoney( | |
| item.productSaleCount!.toDouble())} = ${formatMoney( | |
| item.productTotalPrice!.toDouble())}</div> | |
| <div style='font-size: 10px;'>QQS - ${item.productVatPercent}%</div> | |
| <div style='font-size: 10px;'>MXIK: ${item.productClassCode}</div> | |
| <div style='font-size: 10px;'>Shtrix kod: ${item.productBarcode}</div> | |
| """; | |
| } | |
| // Generate QR code | |
| String qrCodeImage = await generateBase64QRCode(receiptData.ofdQrCodeUrl!); | |
| // HTML content | |
| String htmlContent = """ | |
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <style> | |
| @page { | |
| margin: 0; | |
| } | |
| body { font-family: Arial, sans-serif; margin:0; padding: 0; } | |
| .header { text-align: center; font-size: 12px; } | |
| .row { font-size: 11px; display: flex; justify-content: space-between; } | |
| .divider { border-top: 1px solid black; margin: 10px 0; } | |
| .qr-code { | |
| padding: 10px; | |
| } | |
| img { | |
| width: 150px; /* Adjust size as needed */ | |
| height: 150px; | |
| object-fit: contain; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="header"> | |
| <h4 style="text-align:center">O’zbekiston Respublikasi Vazirlar Mahkamasi huzuridagi Soliq-Servis DUK</h4> | |
| <p>$companyAddress</p> | |
| </div> | |
| <hr class="divider"/> | |
| <div class="row"> | |
| <span>STIR:</span> | |
| <span>$companyStir</span> | |
| </div> | |
| <div class="row"> | |
| <span>Sana:</span> | |
| <span>${getCustomDate(receiptData.ofdDateTime??"")}</span> | |
| </div> | |
| <div class="row"> | |
| <span>Chek raqami:</span> | |
| <span>${receiptData.ofdReceiptSeq}</span> | |
| </div> | |
| <div class="row"> | |
| <span>Kassir:</span><span>$cashier</span> | |
| </div> | |
| <div class="divider"></div> | |
| <!-- Invoice Items --> | |
| $chequeItems | |
| <div class="divider"></div> | |
| <div class="row" style="font-size: 13px; font-weight: bold;"> | |
| <span>Jami:</span> | |
| <span>${formatMoney(receiptData.totalSum!.toDouble())}</span> | |
| </div> | |
| <div class="row"> | |
| <span>QQS:</span> | |
| <span>${formatMoney(receiptData.totalVatSum!.toDouble())}</span> | |
| </div> | |
| <div class="row" style="font-size: 12px; font-weight: bold;"> | |
| <span>To'lov:</span> | |
| <span>${formatMoney(receiptData.totalPay!.toDouble())}</span> | |
| </div> | |
| <hr class="divider"/> | |
| <div class="row"> | |
| <span>Naqd:</span> | |
| <span>${formatMoney(totalCash)}</span> | |
| </div> | |
| <div class="row"> | |
| <span>Karta orqali:</span> | |
| <span>${formatMoney(totalCard)}</span> | |
| </div> | |
| <div class="row"> | |
| <span>Qaytim:</span> | |
| <span>${formatMoney(0.0)}</span> | |
| </div> | |
| <div class="divider" style="border-top: 2px dashed black;"></div> | |
| <div style="text-align: center; font-weight: bold;"> | |
| Fiskal ma'lumotlar | |
| </div> | |
| <div class="row" style="font-size: 11px; font-weight: bold;"> | |
| <span>Virtual Kassa $versionApp version</span><span></span> | |
| </div> | |
| <div class="row" style="font-size: 11px;"> | |
| <span>$cashboxId</span><span></span> | |
| </div> | |
| <div class="row" style="font-size: 11px; font-weight: bold;"> | |
| <span>FM raqami:</span><span>${receiptData.terminalId}</span> | |
| </div> | |
| <div class="row" style="font-size: 11px; font-weight: bold;"> | |
| <span>Chek raqami:</span><span>${receiptData.ofdReceiptSeq}</span> | |
| </div> | |
| <div class="row" style="font-size: 11px; font-weight: bold;"> | |
| <span>Fiskal belgi:</span><span>${receiptData.ofdFiscalSign}</span> | |
| </div> | |
| <div class="qr-code"> | |
| <img src='data:image/png;base64,$qrCodeImage' alt='QR Code'> | |
| </div> | |
| </body> | |
| </html> | |
| """; | |
| // Saving the HTML content to a file | |
| final directory = await getApplicationDocumentsDirectory(); | |
| final filePath = '${directory.path}/receipt.html'; | |
| final file = File(filePath); | |
| await file.writeAsString(htmlContent); | |
| return htmlContent; | |
| } catch (e) { | |
| WriteLOG.writeLog(e.toString()); | |
| return ""; | |
| } | |
| } | |
| static Future<String> generateBase64QRCode(String qrCodeURL) async { | |
| try { | |
| // Create the QrPainter object | |
| final qrCodePainter = QrPainter( | |
| data: qrCodeURL, | |
| version: QrVersions.auto, | |
| gapless: true, | |
| ); | |
| // Convert the QrPainter to a UI Image | |
| final uiImage = await qrCodePainter.toImage(150); // Size 150x150 | |
| // Convert the image to ByteData in PNG format | |
| final byteData = await uiImage.toByteData(format: ui.ImageByteFormat.png); | |
| if (byteData == null) { | |
| throw Exception('Error converting QR code to ByteData'); | |
| } | |
| // Convert the ByteData to Uint8List (needed for base64 encoding) | |
| final pngBytes = byteData.buffer.asUint8List(); | |
| // Encode the bytes to base64 string | |
| final base64String = base64Encode(pngBytes); | |
| return base64String; | |
| } catch (e) { | |
| WriteLOG.writeLog(e.toString()); | |
| return ''; | |
| } | |
| } | |
| // API CALLS | |
| static Future<Response> getOverallData(Request request) async { | |
| try { | |
| final VirtualCashDb virtualCashDb = locator<VirtualCashDb>(); | |
| var result = await virtualCashDb.getTotalPayAndCount(); | |
| return Response.ok( | |
| jsonEncode({'success': true, 'reason': '', 'data' : result}), | |
| headers: {'Content-Type': 'application/json'}, | |
| ); | |
| } catch(e) { | |
| WriteLOG.writeLog("Debug error2 $e"); | |
| return Response.ok( | |
| jsonEncode({'success': false, 'reason': '$e'}), | |
| headers: {'Content-Type': 'application/json'}, | |
| ); | |
| } | |
| } | |
| static Future<Response> getChequeList(Request request) async { | |
| try { | |
| final VirtualCashDb virtualCashDb = locator<VirtualCashDb>(); | |
| var result = await virtualCashDb.getCustomCheques(); | |
| return Response.ok( | |
| jsonEncode({'success': true, 'reason': '', 'data' : result}), | |
| headers: {'Content-Type': 'application/json'}, | |
| ); | |
| } catch(e) { | |
| WriteLOG.writeLog("Debug error2 $e"); | |
| return Response.ok( | |
| jsonEncode({'success': false, 'reason': '$e'}), | |
| headers: {'Content-Type': 'application/json'}, | |
| ); | |
| } | |
| } | |
| static Future<Response> updateIntegrationId(Request request) async { | |
| try { | |
| // Parse the request body | |
| final body = await request.readAsString(); | |
| final data = jsonDecode(body); | |
| // Extract receipt_id and integration_id from the parsed data | |
| final receiptId = data['receipt_id']; | |
| final newIntegrationId = data['integration_id']; | |
| // Validate the input | |
| if (receiptId == null || newIntegrationId == null) { | |
| return Response.badRequest( | |
| body: jsonEncode({'success': false, 'reason': 'Invalid input'}), | |
| headers: {'Content-Type': 'application/json'}, | |
| ); | |
| } | |
| final VirtualCashDb virtualCashDb = locator<VirtualCashDb>(); | |
| await virtualCashDb.updateIntegrationId(receiptId, newIntegrationId); | |
| return Response.ok( | |
| jsonEncode({'success': true, 'reason': '', 'data' : null}), | |
| headers: {'Content-Type': 'application/json'}, | |
| ); | |
| } catch(e) { | |
| WriteLOG.writeLog("Debug error2 $e"); | |
| return Response.ok( | |
| jsonEncode({'success': false, 'reason': '$e'}), | |
| headers: {'Content-Type': 'application/json'}, | |
| ); | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment