369 lines
14 KiB
Dart
369 lines
14 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:intl/intl.dart';
|
|
import 'package:pdf/pdf.dart';
|
|
import 'package:pdf/widgets.dart' as pw;
|
|
import 'package:printing/printing.dart';
|
|
|
|
/// Service for generating and printing warehouse export forms
|
|
class PrintService {
|
|
/// Generate and print a warehouse export form
|
|
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? barcodeData,
|
|
}) async {
|
|
final pdf = pw.Document();
|
|
|
|
// Format current date
|
|
final dt = DateFormat('dd/MM/yyyy HH:mm').format(DateTime.now());
|
|
|
|
// Add page to PDF
|
|
pdf.addPage(
|
|
pw.Page(
|
|
pageFormat: PdfPageFormat.a4,
|
|
margin: const pw.EdgeInsets.all(12),
|
|
build: (pw.Context pdfContext) {
|
|
return pw.Container(
|
|
padding: const pw.EdgeInsets.all(12),
|
|
child: pw.Column(
|
|
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
|
children: [
|
|
// Title
|
|
pw.Center(
|
|
child: pw.Column(
|
|
children: [
|
|
pw.Text(
|
|
'PHIẾU XUẤT KHO',
|
|
style: pw.TextStyle(
|
|
fontSize: 20,
|
|
fontWeight: pw.FontWeight.bold,
|
|
),
|
|
),
|
|
pw.SizedBox(height: 8),
|
|
pw.Text(
|
|
'Công ty TNHH Cơ Khí Chính Xác Minh Thư',
|
|
style: const pw.TextStyle(fontSize: 16),
|
|
),
|
|
pw.SizedBox(height: 4),
|
|
pw.Text(
|
|
warehouseName,
|
|
style: const pw.TextStyle(fontSize: 14),
|
|
),
|
|
pw.SizedBox(height: 4),
|
|
pw.Text(
|
|
'Ngày: $dt',
|
|
style: pw.TextStyle(
|
|
fontSize: 12,
|
|
color: PdfColors.grey700,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
|
|
pw.SizedBox(height: 16),
|
|
|
|
// Product information box
|
|
pw.Container(
|
|
decoration: pw.BoxDecoration(
|
|
border: pw.Border.all(color: PdfColors.black, width: 0.5),
|
|
borderRadius: pw.BorderRadius.circular(8),
|
|
),
|
|
padding: const pw.EdgeInsets.all(8),
|
|
child: pw.Column(
|
|
children: [
|
|
pw.Row(
|
|
children: [
|
|
pw.Expanded(
|
|
child: pw.Column(
|
|
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
|
children: [
|
|
pw.Text(
|
|
'ProductId',
|
|
style: pw.TextStyle(
|
|
fontSize: 10,
|
|
color: PdfColors.grey700,
|
|
),
|
|
),
|
|
pw.SizedBox(height: 2),
|
|
pw.Text(
|
|
'$productId',
|
|
style: pw.TextStyle(
|
|
fontSize: 12,
|
|
fontWeight: pw.FontWeight.bold,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
pw.Expanded(
|
|
child: pw.Column(
|
|
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
|
children: [
|
|
pw.Text(
|
|
'Mã sản phẩm',
|
|
style: pw.TextStyle(
|
|
fontSize: 10,
|
|
color: PdfColors.grey700,
|
|
),
|
|
),
|
|
pw.SizedBox(height: 2),
|
|
pw.Text(
|
|
productCode,
|
|
style: pw.TextStyle(
|
|
fontSize: 12,
|
|
fontWeight: pw.FontWeight.bold,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
pw.SizedBox(height: 8),
|
|
pw.Row(
|
|
children: [
|
|
pw.Expanded(
|
|
child: pw.Column(
|
|
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
|
children: [
|
|
pw.Text(
|
|
'Tên sản phẩm',
|
|
style: pw.TextStyle(
|
|
fontSize: 10,
|
|
color: PdfColors.grey700,
|
|
),
|
|
),
|
|
pw.SizedBox(height: 2),
|
|
pw.Text(
|
|
productName,
|
|
style: pw.TextStyle(
|
|
fontSize: 12,
|
|
fontWeight: pw.FontWeight.bold,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
pw.Expanded(
|
|
child: pw.Column(
|
|
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
|
children: [
|
|
pw.Text(
|
|
'Công đoạn',
|
|
style: pw.TextStyle(
|
|
fontSize: 10,
|
|
color: PdfColors.grey700,
|
|
),
|
|
),
|
|
pw.SizedBox(height: 2),
|
|
pw.Text(
|
|
stageName ?? '-',
|
|
style: pw.TextStyle(
|
|
fontSize: 12,
|
|
fontWeight: pw.FontWeight.bold,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
|
|
pw.SizedBox(height: 12),
|
|
|
|
// Quantities box
|
|
pw.Container(
|
|
decoration: pw.BoxDecoration(
|
|
border: pw.Border.all(color: PdfColors.black, width: 0.5),
|
|
borderRadius: pw.BorderRadius.circular(8),
|
|
),
|
|
padding: const pw.EdgeInsets.all(8),
|
|
child: pw.Column(
|
|
crossAxisAlignment: pw.CrossAxisAlignment.start,
|
|
children: [
|
|
pw.Text(
|
|
'Số lượng:',
|
|
style: pw.TextStyle(
|
|
fontSize: 10,
|
|
color: PdfColors.grey700,
|
|
),
|
|
),
|
|
pw.SizedBox(height: 6),
|
|
pw.Table(
|
|
border: pw.TableBorder.all(
|
|
color: PdfColors.black,
|
|
width: 0.5,
|
|
),
|
|
children: [
|
|
// Header
|
|
pw.TableRow(
|
|
decoration: const pw.BoxDecoration(
|
|
color: PdfColors.grey300,
|
|
),
|
|
children: [
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(8),
|
|
child: pw.Text(
|
|
'Loại',
|
|
style: pw.TextStyle(
|
|
fontWeight: pw.FontWeight.bold,
|
|
),
|
|
),
|
|
),
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(8),
|
|
child: pw.Text(
|
|
'KG',
|
|
style: pw.TextStyle(
|
|
fontWeight: pw.FontWeight.bold,
|
|
),
|
|
),
|
|
),
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(8),
|
|
child: pw.Text(
|
|
'PCS',
|
|
style: pw.TextStyle(
|
|
fontWeight: pw.FontWeight.bold,
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
// Passed quantity row
|
|
pw.TableRow(
|
|
children: [
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(8),
|
|
child: pw.Text('Hàng đạt'),
|
|
),
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(8),
|
|
child: pw.Text(passedKg.toStringAsFixed(2)),
|
|
),
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(8),
|
|
child: pw.Text('$passedPcs'),
|
|
),
|
|
],
|
|
),
|
|
// Issued quantity row
|
|
pw.TableRow(
|
|
children: [
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(8),
|
|
child: pw.Text('Hàng lỗi'),
|
|
),
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(8),
|
|
child: pw.Text(issuedKg.toStringAsFixed(2)),
|
|
),
|
|
pw.Padding(
|
|
padding: const pw.EdgeInsets.all(8),
|
|
child: pw.Text('$issuedPcs'),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
),
|
|
|
|
pw.SizedBox(height: 12),
|
|
|
|
// Responsible person box
|
|
pw.Container(
|
|
decoration: pw.BoxDecoration(
|
|
border: pw.Border.all(color: PdfColors.black, width: 0.5),
|
|
borderRadius: pw.BorderRadius.circular(8),
|
|
),
|
|
padding: const pw.EdgeInsets.all(8),
|
|
child: pw.Row(
|
|
children: [
|
|
pw.Text(
|
|
'Nhân viên kho: ',
|
|
style: pw.TextStyle(
|
|
fontSize: 10,
|
|
color: PdfColors.grey700,
|
|
),
|
|
),
|
|
pw.Text(
|
|
responsibleName ?? '-',
|
|
style: pw.TextStyle(
|
|
fontSize: 12,
|
|
fontWeight: pw.FontWeight.bold,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
|
|
pw.SizedBox(height: 12),
|
|
|
|
// Barcode section
|
|
if (barcodeData != null && barcodeData.isNotEmpty)
|
|
pw.Center(
|
|
child: pw.BarcodeWidget(
|
|
barcode: pw.Barcode.code128(),
|
|
data: barcodeData,
|
|
width: 200,
|
|
height: 60,
|
|
),
|
|
),
|
|
|
|
pw.Spacer(),
|
|
|
|
// Footer signature section
|
|
pw.Row(
|
|
mainAxisAlignment: pw.MainAxisAlignment.center,
|
|
children: [
|
|
pw.Container(
|
|
width: 150,
|
|
child: pw.Column(
|
|
children: [
|
|
pw.Text(
|
|
'Người nhận',
|
|
style: pw.TextStyle(
|
|
fontSize: 10,
|
|
color: PdfColors.grey700,
|
|
),
|
|
),
|
|
pw.SizedBox(height: 40),
|
|
pw.Container(
|
|
height: 1,
|
|
color: PdfColors.grey700,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
),
|
|
);
|
|
|
|
// Show print preview dialog
|
|
await Printing.layoutPdf(
|
|
onLayout: (PdfPageFormat format) async => pdf.save(),
|
|
name: 'warehouse_export_${productCode}_${DateTime.now().millisecondsSinceEpoch}.pdf',
|
|
);
|
|
}
|
|
}
|