asdasdasd

This commit is contained in:
Phuoc Nguyen
2025-10-29 16:31:04 +07:00
parent c12869b01f
commit efcc6306b0
6 changed files with 4351 additions and 17 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -21,16 +21,25 @@ class PrintService {
String? responsibleName,
String? barcodeData,
}) async {
// Load Vietnamese-compatible fonts using PdfGoogleFonts
// Noto Sans has excellent Vietnamese character support
final fontRegular = await PdfGoogleFonts.notoSansRegular();
final fontBold = await PdfGoogleFonts.notoSansBold();
final pdf = pw.Document();
// Format current date
final dt = DateFormat('dd/MM/yyyy HH:mm').format(DateTime.now());
// Add page to PDF
// Add page to PDF with theme for Vietnamese font support
pdf.addPage(
pw.Page(
pageFormat: PdfPageFormat.a4,
margin: const pw.EdgeInsets.all(12),
theme: pw.ThemeData.withFont(
base: fontRegular,
bold: fontBold,
),
build: (pw.Context pdfContext) {
return pw.Container(
padding: const pw.EdgeInsets.all(12),

View File

@@ -362,12 +362,7 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
title: 'Thêm số lượng mới',
icon: Icons.add_circle_outline,
children: [
_buildTextField(
label: 'Số lượng đạt',
controller: _passedQuantityController,
keyboardType: TextInputType.number,
theme: theme,
),
_buildTextField(
label: 'Khối lượng đạt (kg)',
controller: _passedWeightController,
@@ -375,8 +370,8 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
theme: theme,
),
_buildTextField(
label: 'Số lượng lỗi',
controller: _issuedQuantityController,
label: 'Số lượng đạt',
controller: _passedQuantityController,
keyboardType: TextInputType.number,
theme: theme,
),
@@ -386,13 +381,20 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
keyboardType: const TextInputType.numberWithOptions(decimal: true),
theme: theme,
),
_buildTextField(
label: 'Số lượng lỗi',
controller: _issuedQuantityController,
keyboardType: TextInputType.number,
theme: theme,
),
],
),
_buildSectionCard(theme: theme, title: "Nhân viên", icon: Icons.people, children: [
// Warehouse User Dropdown
// Warehouse User Dropdown (Required)
_buildUserDropdown(
label: 'Người dùng kho',
label: 'Người dùng kho *',
value: _selectedWarehouseUser,
users: ref.watch(usersListProvider)
.where((user) => user.isWareHouseUser)
@@ -405,9 +407,9 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
theme: theme,
),
const SizedBox(height: 8),
// All Employees Dropdown
// All Employees Dropdown (Required)
_buildUserDropdown(
label: 'Nhân viên',
label: 'Nhân viên *',
value: _selectedEmployee,
users: ref.watch(usersListProvider),
onChanged: (user) {
@@ -448,6 +450,18 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
}
Future<void> _printQuantities(ProductStageEntity stage) async {
// Validate that both users are selected
if (_selectedEmployee == null || _selectedWarehouseUser == null) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Vui lòng chọn cả Nhân viên và Người dùng kho trước khi in'),
backgroundColor: Colors.orange,
duration: Duration(seconds: 3),
),
);
return;
}
// Get the current quantity values (entered by user or use current values)
final passedQuantity = int.tryParse(_passedQuantityController.text) ?? 0;
final passedWeight = double.tryParse(_passedWeightController.text) ?? 0.0;
@@ -461,9 +475,7 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
final finalIssuedKg = issuedWeight > 0.0 ? issuedWeight : stage.issuedQuantityWeight;
// Get responsible user name
final responsibleName = _selectedWarehouseUser != null
? '${_selectedWarehouseUser!.name} ${_selectedWarehouseUser!.firstName}'
: null;
final responsibleName = '${_selectedWarehouseUser!.name} ${_selectedWarehouseUser!.firstName}';
// Generate barcode data (using product code or product ID)
final barcodeData = stage.productCode.isNotEmpty
@@ -521,8 +533,9 @@ class _ProductDetailPageState extends ConsumerState<ProductDetailPage> {
if (_selectedEmployee == null || _selectedWarehouseUser == null) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Vui lòng chọn cả Nhân viên và Người dùng kho'),
content: Text('Vui lòng chọn cả Nhân viên và Người dùng kho trước khi lưu'),
backgroundColor: Colors.orange,
duration: Duration(seconds: 3),
),
);
return;

View File

@@ -480,6 +480,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "13.2.5"
google_fonts:
dependency: "direct main"
description:
name: google_fonts
sha256: "517b20870220c48752eafa0ba1a797a092fb22df0d89535fd9991e86ee2cdd9c"
url: "https://pub.dev"
source: hosted
version: "6.3.2"
graphs:
dependency: transitive
description:

View File

@@ -41,6 +41,7 @@ dependencies:
printing: ^5.13.4
pdf: ^3.11.3
barcode_widget: ^2.0.4
google_fonts: ^6.2.1
dev_dependencies:
flutter_test:
@@ -63,6 +64,7 @@ flutter:
# Assets
assets:
- assets/app_icon.jpg
- assets/fonts/
# Flutter Launcher Icons Configuration
flutter_launcher_icons: