Compare commits

..

3 Commits

Author SHA1 Message Date
Phuoc Nguyen
2ff639fc42 sunmi 2025-11-04 18:10:54 +07:00
Phuoc Nguyen
1cfdd2c0c6 update. save => print 2025-11-04 09:29:35 +07:00
ff25363a19 sunmi 2025-11-04 08:12:13 +07:00
7 changed files with 235 additions and 15 deletions

View File

@@ -38,11 +38,11 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS: SPEC CHECKSUMS:
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
flutter_secure_storage: 1ed9476fba7e7a782b22888f956cce43e2c62f13 flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12
mobile_scanner: 9157936403f5a0644ca3779a38ff8404c5434a93 mobile_scanner: 77265f3dc8d580810e91849d4a0811a90467ed5e
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
printing: 54ff03f28fe9ba3aa93358afb80a8595a071dd07 printing: 233e1b73bd1f4a05615548e9b5a324c98588640b
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0 sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d
PODFILE CHECKSUM: 3c63482e143d1b91d2d2560aee9fb04ecc74ac7e PODFILE CHECKSUM: 3c63482e143d1b91d2d2560aee9fb04ecc74ac7e

View File

@@ -0,0 +1,210 @@
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:sunmi_printer_plus/sunmi_printer_plus.dart';
/// Service for printing to Sunmi thermal printers
class SunmiService {
/// Print warehouse export form to Sunmi printer
static Future<void> printWarehouseExport({
required BuildContext context,
required String warehouseName,
required int productId,
required String productCode,
required String productName,
String? stageName,
required double passedKg,
required int passedPcs,
required double issuedKg,
required int issuedPcs,
String? responsibleName,
String? receiverName,
String? barcodeData,
}) async {
try {
// Format current date
final dt = DateFormat('dd/MM/yyyy HH:mm').format(DateTime.now());
// Title - PHIẾU XUẤT KHO
await SunmiPrinter.printText(
'PHIEU XUAT KHO',
style: SunmiTextStyle(
align: SunmiPrintAlign.CENTER,
bold: true,
fontSize: 48,
),
);
await SunmiPrinter.lineWrap(1);
// Company name
await SunmiPrinter.printText(
'Cong ty TNHH Co Khi Chinh Xac Minh Thu',
style: SunmiTextStyle(
align: SunmiPrintAlign.CENTER,
fontSize: 32,
),
);
await SunmiPrinter.lineWrap(1);
// Warehouse name
await SunmiPrinter.printText(
warehouseName,
style: SunmiTextStyle(align: SunmiPrintAlign.CENTER),
);
await SunmiPrinter.lineWrap(1);
// Date
await SunmiPrinter.printText(
'Ngay: $dt',
style: SunmiTextStyle(align: SunmiPrintAlign.CENTER),
);
await SunmiPrinter.lineWrap(2);
// Separator line
await SunmiPrinter.line();
await SunmiPrinter.lineWrap(1);
// Product information
await SunmiPrinter.printText(
'THONG TIN SAN PHAM',
style: SunmiTextStyle(
align: SunmiPrintAlign.LEFT,
bold: true,
),
);
await SunmiPrinter.lineWrap(1);
// ProductId
await SunmiPrinter.printText(
'ProductId: $productId',
style: SunmiTextStyle(align: SunmiPrintAlign.LEFT),
);
await SunmiPrinter.lineWrap(1);
// Product Code
await SunmiPrinter.printText(
'Ma san pham: $productCode',
style: SunmiTextStyle(align: SunmiPrintAlign.LEFT),
);
await SunmiPrinter.lineWrap(1);
// Product Name
await SunmiPrinter.printText(
'Ten san pham: $productName',
style: SunmiTextStyle(align: SunmiPrintAlign.LEFT),
);
await SunmiPrinter.lineWrap(1);
// Stage Name
await SunmiPrinter.printText(
'Cong doan: ${stageName ?? '-'}',
style: SunmiTextStyle(align: SunmiPrintAlign.LEFT),
);
await SunmiPrinter.lineWrap(2);
// Separator line
await SunmiPrinter.line();
await SunmiPrinter.lineWrap(1);
// Quantities
await SunmiPrinter.printText(
'SO LUONG',
style: SunmiTextStyle(
align: SunmiPrintAlign.LEFT,
bold: true,
),
);
await SunmiPrinter.lineWrap(1);
// Table header
await SunmiPrinter.printText(
'Loai KG PCS',
style: SunmiTextStyle(align: SunmiPrintAlign.LEFT),
);
await SunmiPrinter.line();
// Passed quantity (Hàng đạt)
final passedLine =
'Hang dat ${passedKg.toStringAsFixed(2).padLeft(7)} ${passedPcs.toString().padLeft(5)}';
await SunmiPrinter.printText(
passedLine,
style: SunmiTextStyle(align: SunmiPrintAlign.LEFT),
);
// Issued quantity (Hàng lỗi)
final issuedLine =
'Hang loi ${issuedKg.toStringAsFixed(2).padLeft(7)} ${issuedPcs.toString().padLeft(5)}';
await SunmiPrinter.printText(
issuedLine,
style: SunmiTextStyle(align: SunmiPrintAlign.LEFT),
);
await SunmiPrinter.lineWrap(2);
// Separator line
await SunmiPrinter.line();
await SunmiPrinter.lineWrap(1);
// Responsible person
await SunmiPrinter.printText(
'Nhan vien kho: ${responsibleName ?? '-'}',
style: SunmiTextStyle(align: SunmiPrintAlign.LEFT),
);
await SunmiPrinter.lineWrap(1);
// Receiver
await SunmiPrinter.printText(
'Nhan vien tiep nhan: ${receiverName ?? '-'}',
style: SunmiTextStyle(align: SunmiPrintAlign.LEFT),
);
await SunmiPrinter.lineWrap(2);
// Barcode
if (barcodeData != null && barcodeData.isNotEmpty) {
await SunmiPrinter.line();
await SunmiPrinter.printBarCode(
barcodeData,
style: SunmiBarcodeStyle(
type: SunmiBarcodeType.CODE128,
textPos: SunmiBarcodeTextPos.TEXT_UNDER,
height: 100,
align: SunmiPrintAlign.CENTER,
),
);
await SunmiPrinter.lineWrap(2);
}
// Footer
await SunmiPrinter.line();
await SunmiPrinter.printText(
'Nguoi nhan',
style: SunmiTextStyle(align: SunmiPrintAlign.CENTER),
);
await SunmiPrinter.lineWrap(4);
// Cut paper
await SunmiPrinter.cutPaper();
// Show success message
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Đã in thành công!'),
backgroundColor: Colors.green,
duration: Duration(seconds: 2),
),
);
}
} catch (e) {
// Show error message
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Lỗi khi in: ${e.toString()}'),
backgroundColor: Colors.red,
duration: const Duration(seconds: 3),
),
);
}
rethrow;
}
}
}

View File

@@ -102,7 +102,7 @@ class ProductsRemoteDataSourceImpl implements ProductsRemoteDataSource {
// The API returns a list of stages for the product // The API returns a list of stages for the product
final list = json as List; final list = json as List;
if (list.isEmpty) { if (list.isEmpty) {
throw const ServerException('Product stages not found'); throw const ServerException('Không tìm thấy sản phẩm');
} }
// Parse all stages from the list // Parse all stages from the list
return list return list

View File

@@ -4,8 +4,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mobile_scanner/mobile_scanner.dart'; import 'package:mobile_scanner/mobile_scanner.dart';
import '../../../../core/di/providers.dart'; import '../../../../core/di/providers.dart';
import '../../../../core/router/app_router.dart'; import '../../../../core/services/sunmi_service.dart';
import '../../../../core/services/print_service.dart';
import '../../../../core/storage/secure_storage.dart'; import '../../../../core/storage/secure_storage.dart';
import '../../../../core/utils/text_utils.dart'; import '../../../../core/utils/text_utils.dart';
import '../../../users/domain/entities/user_entity.dart'; import '../../../users/domain/entities/user_entity.dart';
@@ -94,7 +93,7 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
// Get stored current user ID from secure storage // Get stored current user ID from secure storage
final secureStorage = SecureStorage(); final secureStorage = SecureStorage();
final currentUserId = await secureStorage.getCurrentUserId(); final currentUserId = await secureStorage.getCurrentUserId();
print('user $currentUserId');
if (currentUserId == null) { if (currentUserId == null) {
return; return;
} }
@@ -419,7 +418,7 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
Text( Text(
'Error', 'Lỗi',
style: theme.textTheme.titleLarge?.copyWith( style: theme.textTheme.titleLarge?.copyWith(
color: theme.colorScheme.error, color: theme.colorScheme.error,
), ),
@@ -730,7 +729,7 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
: 'P${stage.productId}'; : 'P${stage.productId}';
try { try {
await PrintService.printWarehouseExport( await SunmiService.printWarehouseExport(
context: context, context: context,
warehouseName: widget.warehouseName, warehouseName: widget.warehouseName,
productId: stage.productId, productId: stage.productId,
@@ -749,7 +748,7 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
if (mounted) { if (mounted) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: Text('Error printing: ${e.toString()}'), content: Text('Lỗi khi in: ${e.toString()}'),
backgroundColor: Colors.red, backgroundColor: Colors.red,
duration: const Duration(seconds: 3), duration: const Duration(seconds: 3),
), ),
@@ -789,8 +788,7 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
return; return;
} }
// Print before saving to API
await _printQuantities(stage);
// Show loading dialog // Show loading dialog
showDialog( showDialog(
@@ -864,6 +862,9 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
), ),
); );
// Print before saving to API
await _printQuantities(stage);
// Refresh the product detail to show updated quantities // Refresh the product detail to show updated quantities
await ref.read(productDetailProvider(_providerKey).notifier).refreshProductDetail( await ref.read(productDetailProvider(_providerKey).notifier).refreshProductDetail(
widget.warehouseId, widget.warehouseId,

View File

@@ -33,7 +33,7 @@ class MyApp extends ConsumerWidget {
final router = ref.watch(appRouterProvider); final router = ref.watch(appRouterProvider);
return MaterialApp.router( return MaterialApp.router(
title: 'Warehouse Manager', title: 'MinhThu',
theme: AppTheme.lightTheme, theme: AppTheme.lightTheme,
darkTheme: AppTheme.darkTheme, darkTheme: AppTheme.darkTheme,
themeMode: ThemeMode.system, themeMode: ThemeMode.system,

View File

@@ -1029,6 +1029,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.4.1" version: "1.4.1"
sunmi_printer_plus:
dependency: "direct main"
description:
name: sunmi_printer_plus
sha256: "77293b7da16bdf3805c5a24ea41731978e8a31da99c3fca38a658a0778450b78"
url: "https://pub.dev"
source: hosted
version: "4.1.1"
synchronized: synchronized:
dependency: transitive dependency: transitive
description: description:

View File

@@ -42,6 +42,7 @@ dependencies:
pdf: ^3.11.3 pdf: ^3.11.3
barcode_widget: ^2.0.4 barcode_widget: ^2.0.4
google_fonts: ^6.2.1 google_fonts: ^6.2.1
sunmi_printer_plus: ^4.1.1
dev_dependencies: dev_dependencies:
flutter_test: flutter_test: