diff --git a/lib/app/data/database.dart b/lib/app/data/database.dart index 877192f..31e2f68 100644 --- a/lib/app/data/database.dart +++ b/lib/app/data/database.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'dart:io'; +import 'package:collection/collection.dart'; import 'package:drift/drift.dart'; import 'package:drift/native.dart'; import 'package:path_provider/path_provider.dart'; @@ -19,6 +20,7 @@ part 'users_dao.dart'; @DriftDatabase( tables: [ Users, + Products, ProductArrivals, ProductArrivalPackages, ProductArrivalUnloadPackages, @@ -92,7 +94,7 @@ class AppDataStore extends _$AppDataStore { } @override - int get schemaVersion => 11; + int get schemaVersion => 12; @override MigrationStrategy get migration => MigrationStrategy( diff --git a/lib/app/data/database.g.dart b/lib/app/data/database.g.dart index 5a0037c..3fec072 100644 --- a/lib/app/data/database.g.dart +++ b/lib/app/data/database.g.dart @@ -406,6 +406,300 @@ class $UsersTable extends Users with TableInfo<$UsersTable, User> { const JsonIntListConverter(); } +class Product extends DataClass implements Insertable { + final int id; + final String name; + final String? article; + final String? barcodeCode; + final String? barcodeType; + Product( + {required this.id, + required this.name, + this.article, + this.barcodeCode, + this.barcodeType}); + factory Product.fromData(Map data, {String? prefix}) { + final effectivePrefix = prefix ?? ''; + return Product( + id: const IntType() + .mapFromDatabaseResponse(data['${effectivePrefix}id'])!, + name: const StringType() + .mapFromDatabaseResponse(data['${effectivePrefix}name'])!, + article: const StringType() + .mapFromDatabaseResponse(data['${effectivePrefix}article']), + barcodeCode: const StringType() + .mapFromDatabaseResponse(data['${effectivePrefix}barcode_code']), + barcodeType: const StringType() + .mapFromDatabaseResponse(data['${effectivePrefix}barcode_type']), + ); + } + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + map['id'] = Variable(id); + map['name'] = Variable(name); + if (!nullToAbsent || article != null) { + map['article'] = Variable(article); + } + if (!nullToAbsent || barcodeCode != null) { + map['barcode_code'] = Variable(barcodeCode); + } + if (!nullToAbsent || barcodeType != null) { + map['barcode_type'] = Variable(barcodeType); + } + return map; + } + + ProductsCompanion toCompanion(bool nullToAbsent) { + return ProductsCompanion( + id: Value(id), + name: Value(name), + article: article == null && nullToAbsent + ? const Value.absent() + : Value(article), + barcodeCode: barcodeCode == null && nullToAbsent + ? const Value.absent() + : Value(barcodeCode), + barcodeType: barcodeType == null && nullToAbsent + ? const Value.absent() + : Value(barcodeType), + ); + } + + factory Product.fromJson(Map json, + {ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return Product( + id: serializer.fromJson(json['id']), + name: serializer.fromJson(json['name']), + article: serializer.fromJson(json['article']), + barcodeCode: serializer.fromJson(json['barcodeCode']), + barcodeType: serializer.fromJson(json['barcodeType']), + ); + } + @override + Map toJson({ValueSerializer? serializer}) { + serializer ??= driftRuntimeOptions.defaultSerializer; + return { + 'id': serializer.toJson(id), + 'name': serializer.toJson(name), + 'article': serializer.toJson(article), + 'barcodeCode': serializer.toJson(barcodeCode), + 'barcodeType': serializer.toJson(barcodeType), + }; + } + + Product copyWith( + {int? id, + String? name, + String? article, + String? barcodeCode, + String? barcodeType}) => + Product( + id: id ?? this.id, + name: name ?? this.name, + article: article ?? this.article, + barcodeCode: barcodeCode ?? this.barcodeCode, + barcodeType: barcodeType ?? this.barcodeType, + ); + @override + String toString() { + return (StringBuffer('Product(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('article: $article, ') + ..write('barcodeCode: $barcodeCode, ') + ..write('barcodeType: $barcodeType') + ..write(')')) + .toString(); + } + + @override + int get hashCode => Object.hash(id, name, article, barcodeCode, barcodeType); + @override + bool operator ==(Object other) => + identical(this, other) || + (other is Product && + other.id == this.id && + other.name == this.name && + other.article == this.article && + other.barcodeCode == this.barcodeCode && + other.barcodeType == this.barcodeType); +} + +class ProductsCompanion extends UpdateCompanion { + final Value id; + final Value name; + final Value article; + final Value barcodeCode; + final Value barcodeType; + const ProductsCompanion({ + this.id = const Value.absent(), + this.name = const Value.absent(), + this.article = const Value.absent(), + this.barcodeCode = const Value.absent(), + this.barcodeType = const Value.absent(), + }); + ProductsCompanion.insert({ + this.id = const Value.absent(), + required String name, + this.article = const Value.absent(), + this.barcodeCode = const Value.absent(), + this.barcodeType = const Value.absent(), + }) : name = Value(name); + static Insertable custom({ + Expression? id, + Expression? name, + Expression? article, + Expression? barcodeCode, + Expression? barcodeType, + }) { + return RawValuesInsertable({ + if (id != null) 'id': id, + if (name != null) 'name': name, + if (article != null) 'article': article, + if (barcodeCode != null) 'barcode_code': barcodeCode, + if (barcodeType != null) 'barcode_type': barcodeType, + }); + } + + ProductsCompanion copyWith( + {Value? id, + Value? name, + Value? article, + Value? barcodeCode, + Value? barcodeType}) { + return ProductsCompanion( + id: id ?? this.id, + name: name ?? this.name, + article: article ?? this.article, + barcodeCode: barcodeCode ?? this.barcodeCode, + barcodeType: barcodeType ?? this.barcodeType, + ); + } + + @override + Map toColumns(bool nullToAbsent) { + final map = {}; + if (id.present) { + map['id'] = Variable(id.value); + } + if (name.present) { + map['name'] = Variable(name.value); + } + if (article.present) { + map['article'] = Variable(article.value); + } + if (barcodeCode.present) { + map['barcode_code'] = Variable(barcodeCode.value); + } + if (barcodeType.present) { + map['barcode_type'] = Variable(barcodeType.value); + } + return map; + } + + @override + String toString() { + return (StringBuffer('ProductsCompanion(') + ..write('id: $id, ') + ..write('name: $name, ') + ..write('article: $article, ') + ..write('barcodeCode: $barcodeCode, ') + ..write('barcodeType: $barcodeType') + ..write(')')) + .toString(); + } +} + +class $ProductsTable extends Products with TableInfo<$ProductsTable, Product> { + @override + final GeneratedDatabase attachedDatabase; + final String? _alias; + $ProductsTable(this.attachedDatabase, [this._alias]); + final VerificationMeta _idMeta = const VerificationMeta('id'); + @override + late final GeneratedColumn id = GeneratedColumn( + 'id', aliasedName, false, + type: const IntType(), + requiredDuringInsert: false, + defaultConstraints: 'PRIMARY KEY AUTOINCREMENT'); + final VerificationMeta _nameMeta = const VerificationMeta('name'); + @override + late final GeneratedColumn name = GeneratedColumn( + 'name', aliasedName, false, + type: const StringType(), requiredDuringInsert: true); + final VerificationMeta _articleMeta = const VerificationMeta('article'); + @override + late final GeneratedColumn article = GeneratedColumn( + 'article', aliasedName, true, + type: const StringType(), requiredDuringInsert: false); + final VerificationMeta _barcodeCodeMeta = + const VerificationMeta('barcodeCode'); + @override + late final GeneratedColumn barcodeCode = GeneratedColumn( + 'barcode_code', aliasedName, true, + type: const StringType(), requiredDuringInsert: false); + final VerificationMeta _barcodeTypeMeta = + const VerificationMeta('barcodeType'); + @override + late final GeneratedColumn barcodeType = GeneratedColumn( + 'barcode_type', aliasedName, true, + type: const StringType(), requiredDuringInsert: false); + @override + List get $columns => + [id, name, article, barcodeCode, barcodeType]; + @override + String get aliasedName => _alias ?? 'products'; + @override + String get actualTableName => 'products'; + @override + VerificationContext validateIntegrity(Insertable instance, + {bool isInserting = false}) { + final context = VerificationContext(); + final data = instance.toColumns(true); + if (data.containsKey('id')) { + context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta)); + } + if (data.containsKey('name')) { + context.handle( + _nameMeta, name.isAcceptableOrUnknown(data['name']!, _nameMeta)); + } else if (isInserting) { + context.missing(_nameMeta); + } + if (data.containsKey('article')) { + context.handle(_articleMeta, + article.isAcceptableOrUnknown(data['article']!, _articleMeta)); + } + if (data.containsKey('barcode_code')) { + context.handle( + _barcodeCodeMeta, + barcodeCode.isAcceptableOrUnknown( + data['barcode_code']!, _barcodeCodeMeta)); + } + if (data.containsKey('barcode_type')) { + context.handle( + _barcodeTypeMeta, + barcodeType.isAcceptableOrUnknown( + data['barcode_type']!, _barcodeTypeMeta)); + } + return context; + } + + @override + Set get $primaryKey => {id}; + @override + Product map(Map data, {String? tablePrefix}) { + return Product.fromData(data, + prefix: tablePrefix != null ? '$tablePrefix.' : null); + } + + @override + $ProductsTable createAlias(String alias) { + return $ProductsTable(attachedDatabase, alias); + } +} + class Storage extends DataClass implements Insertable { final int id; final String name; @@ -2014,13 +2308,11 @@ class ProductArrivalPackageLine extends DataClass final int id; final int productArrivalPackageId; final int productId; - final String productName; final int amount; ProductArrivalPackageLine( {required this.id, required this.productArrivalPackageId, required this.productId, - required this.productName, required this.amount}); factory ProductArrivalPackageLine.fromData(Map data, {String? prefix}) { @@ -2032,8 +2324,6 @@ class ProductArrivalPackageLine extends DataClass data['${effectivePrefix}product_arrival_package_id'])!, productId: const IntType() .mapFromDatabaseResponse(data['${effectivePrefix}product_id'])!, - productName: const StringType() - .mapFromDatabaseResponse(data['${effectivePrefix}product_name'])!, amount: const IntType() .mapFromDatabaseResponse(data['${effectivePrefix}amount'])!, ); @@ -2044,7 +2334,6 @@ class ProductArrivalPackageLine extends DataClass map['id'] = Variable(id); map['product_arrival_package_id'] = Variable(productArrivalPackageId); map['product_id'] = Variable(productId); - map['product_name'] = Variable(productName); map['amount'] = Variable(amount); return map; } @@ -2054,7 +2343,6 @@ class ProductArrivalPackageLine extends DataClass id: Value(id), productArrivalPackageId: Value(productArrivalPackageId), productId: Value(productId), - productName: Value(productName), amount: Value(amount), ); } @@ -2067,7 +2355,6 @@ class ProductArrivalPackageLine extends DataClass productArrivalPackageId: serializer.fromJson(json['productArrivalPackageId']), productId: serializer.fromJson(json['productId']), - productName: serializer.fromJson(json['productName']), amount: serializer.fromJson(json['amount']), ); } @@ -2079,7 +2366,6 @@ class ProductArrivalPackageLine extends DataClass 'productArrivalPackageId': serializer.toJson(productArrivalPackageId), 'productId': serializer.toJson(productId), - 'productName': serializer.toJson(productName), 'amount': serializer.toJson(amount), }; } @@ -2088,14 +2374,12 @@ class ProductArrivalPackageLine extends DataClass {int? id, int? productArrivalPackageId, int? productId, - String? productName, int? amount}) => ProductArrivalPackageLine( id: id ?? this.id, productArrivalPackageId: productArrivalPackageId ?? this.productArrivalPackageId, productId: productId ?? this.productId, - productName: productName ?? this.productName, amount: amount ?? this.amount, ); @override @@ -2104,7 +2388,6 @@ class ProductArrivalPackageLine extends DataClass ..write('id: $id, ') ..write('productArrivalPackageId: $productArrivalPackageId, ') ..write('productId: $productId, ') - ..write('productName: $productName, ') ..write('amount: $amount') ..write(')')) .toString(); @@ -2112,7 +2395,7 @@ class ProductArrivalPackageLine extends DataClass @override int get hashCode => - Object.hash(id, productArrivalPackageId, productId, productName, amount); + Object.hash(id, productArrivalPackageId, productId, amount); @override bool operator ==(Object other) => identical(this, other) || @@ -2120,7 +2403,6 @@ class ProductArrivalPackageLine extends DataClass other.id == this.id && other.productArrivalPackageId == this.productArrivalPackageId && other.productId == this.productId && - other.productName == this.productName && other.amount == this.amount); } @@ -2129,30 +2411,25 @@ class ProductArrivalPackageLinesCompanion final Value id; final Value productArrivalPackageId; final Value productId; - final Value productName; final Value amount; const ProductArrivalPackageLinesCompanion({ this.id = const Value.absent(), this.productArrivalPackageId = const Value.absent(), this.productId = const Value.absent(), - this.productName = const Value.absent(), this.amount = const Value.absent(), }); ProductArrivalPackageLinesCompanion.insert({ this.id = const Value.absent(), required int productArrivalPackageId, required int productId, - required String productName, required int amount, }) : productArrivalPackageId = Value(productArrivalPackageId), productId = Value(productId), - productName = Value(productName), amount = Value(amount); static Insertable custom({ Expression? id, Expression? productArrivalPackageId, Expression? productId, - Expression? productName, Expression? amount, }) { return RawValuesInsertable({ @@ -2160,7 +2437,6 @@ class ProductArrivalPackageLinesCompanion if (productArrivalPackageId != null) 'product_arrival_package_id': productArrivalPackageId, if (productId != null) 'product_id': productId, - if (productName != null) 'product_name': productName, if (amount != null) 'amount': amount, }); } @@ -2169,14 +2445,12 @@ class ProductArrivalPackageLinesCompanion {Value? id, Value? productArrivalPackageId, Value? productId, - Value? productName, Value? amount}) { return ProductArrivalPackageLinesCompanion( id: id ?? this.id, productArrivalPackageId: productArrivalPackageId ?? this.productArrivalPackageId, productId: productId ?? this.productId, - productName: productName ?? this.productName, amount: amount ?? this.amount, ); } @@ -2194,9 +2468,6 @@ class ProductArrivalPackageLinesCompanion if (productId.present) { map['product_id'] = Variable(productId.value); } - if (productName.present) { - map['product_name'] = Variable(productName.value); - } if (amount.present) { map['amount'] = Variable(amount.value); } @@ -2209,7 +2480,6 @@ class ProductArrivalPackageLinesCompanion ..write('id: $id, ') ..write('productArrivalPackageId: $productArrivalPackageId, ') ..write('productId: $productId, ') - ..write('productName: $productName, ') ..write('amount: $amount') ..write(')')) .toString(); @@ -2243,13 +2513,9 @@ class $ProductArrivalPackageLinesTable extends ProductArrivalPackageLines @override late final GeneratedColumn productId = GeneratedColumn( 'product_id', aliasedName, false, - type: const IntType(), requiredDuringInsert: true); - final VerificationMeta _productNameMeta = - const VerificationMeta('productName'); - @override - late final GeneratedColumn productName = GeneratedColumn( - 'product_name', aliasedName, false, - type: const StringType(), requiredDuringInsert: true); + type: const IntType(), + requiredDuringInsert: true, + defaultConstraints: 'REFERENCES products (id) ON DELETE CASCADE'); final VerificationMeta _amountMeta = const VerificationMeta('amount'); @override late final GeneratedColumn amount = GeneratedColumn( @@ -2257,7 +2523,7 @@ class $ProductArrivalPackageLinesTable extends ProductArrivalPackageLines type: const IntType(), requiredDuringInsert: true); @override List get $columns => - [id, productArrivalPackageId, productId, productName, amount]; + [id, productArrivalPackageId, productId, amount]; @override String get aliasedName => _alias ?? 'product_arrival_package_lines'; @override @@ -2286,14 +2552,6 @@ class $ProductArrivalPackageLinesTable extends ProductArrivalPackageLines } else if (isInserting) { context.missing(_productIdMeta); } - if (data.containsKey('product_name')) { - context.handle( - _productNameMeta, - productName.isAcceptableOrUnknown( - data['product_name']!, _productNameMeta)); - } else if (isInserting) { - context.missing(_productNameMeta); - } if (data.containsKey('amount')) { context.handle(_amountMeta, amount.isAcceptableOrUnknown(data['amount']!, _amountMeta)); @@ -2620,13 +2878,11 @@ class ProductArrivalPackageNewLine extends DataClass final int id; final int productArrivalPackageId; final int productId; - final String productName; final int amount; ProductArrivalPackageNewLine( {required this.id, required this.productArrivalPackageId, required this.productId, - required this.productName, required this.amount}); factory ProductArrivalPackageNewLine.fromData(Map data, {String? prefix}) { @@ -2638,8 +2894,6 @@ class ProductArrivalPackageNewLine extends DataClass data['${effectivePrefix}product_arrival_package_id'])!, productId: const IntType() .mapFromDatabaseResponse(data['${effectivePrefix}product_id'])!, - productName: const StringType() - .mapFromDatabaseResponse(data['${effectivePrefix}product_name'])!, amount: const IntType() .mapFromDatabaseResponse(data['${effectivePrefix}amount'])!, ); @@ -2650,7 +2904,6 @@ class ProductArrivalPackageNewLine extends DataClass map['id'] = Variable(id); map['product_arrival_package_id'] = Variable(productArrivalPackageId); map['product_id'] = Variable(productId); - map['product_name'] = Variable(productName); map['amount'] = Variable(amount); return map; } @@ -2660,7 +2913,6 @@ class ProductArrivalPackageNewLine extends DataClass id: Value(id), productArrivalPackageId: Value(productArrivalPackageId), productId: Value(productId), - productName: Value(productName), amount: Value(amount), ); } @@ -2673,7 +2925,6 @@ class ProductArrivalPackageNewLine extends DataClass productArrivalPackageId: serializer.fromJson(json['productArrivalPackageId']), productId: serializer.fromJson(json['productId']), - productName: serializer.fromJson(json['productName']), amount: serializer.fromJson(json['amount']), ); } @@ -2685,7 +2936,6 @@ class ProductArrivalPackageNewLine extends DataClass 'productArrivalPackageId': serializer.toJson(productArrivalPackageId), 'productId': serializer.toJson(productId), - 'productName': serializer.toJson(productName), 'amount': serializer.toJson(amount), }; } @@ -2694,14 +2944,12 @@ class ProductArrivalPackageNewLine extends DataClass {int? id, int? productArrivalPackageId, int? productId, - String? productName, int? amount}) => ProductArrivalPackageNewLine( id: id ?? this.id, productArrivalPackageId: productArrivalPackageId ?? this.productArrivalPackageId, productId: productId ?? this.productId, - productName: productName ?? this.productName, amount: amount ?? this.amount, ); @override @@ -2710,7 +2958,6 @@ class ProductArrivalPackageNewLine extends DataClass ..write('id: $id, ') ..write('productArrivalPackageId: $productArrivalPackageId, ') ..write('productId: $productId, ') - ..write('productName: $productName, ') ..write('amount: $amount') ..write(')')) .toString(); @@ -2718,7 +2965,7 @@ class ProductArrivalPackageNewLine extends DataClass @override int get hashCode => - Object.hash(id, productArrivalPackageId, productId, productName, amount); + Object.hash(id, productArrivalPackageId, productId, amount); @override bool operator ==(Object other) => identical(this, other) || @@ -2726,7 +2973,6 @@ class ProductArrivalPackageNewLine extends DataClass other.id == this.id && other.productArrivalPackageId == this.productArrivalPackageId && other.productId == this.productId && - other.productName == this.productName && other.amount == this.amount); } @@ -2735,30 +2981,25 @@ class ProductArrivalPackageNewLinesCompanion final Value id; final Value productArrivalPackageId; final Value productId; - final Value productName; final Value amount; const ProductArrivalPackageNewLinesCompanion({ this.id = const Value.absent(), this.productArrivalPackageId = const Value.absent(), this.productId = const Value.absent(), - this.productName = const Value.absent(), this.amount = const Value.absent(), }); ProductArrivalPackageNewLinesCompanion.insert({ this.id = const Value.absent(), required int productArrivalPackageId, required int productId, - required String productName, required int amount, }) : productArrivalPackageId = Value(productArrivalPackageId), productId = Value(productId), - productName = Value(productName), amount = Value(amount); static Insertable custom({ Expression? id, Expression? productArrivalPackageId, Expression? productId, - Expression? productName, Expression? amount, }) { return RawValuesInsertable({ @@ -2766,7 +3007,6 @@ class ProductArrivalPackageNewLinesCompanion if (productArrivalPackageId != null) 'product_arrival_package_id': productArrivalPackageId, if (productId != null) 'product_id': productId, - if (productName != null) 'product_name': productName, if (amount != null) 'amount': amount, }); } @@ -2775,14 +3015,12 @@ class ProductArrivalPackageNewLinesCompanion {Value? id, Value? productArrivalPackageId, Value? productId, - Value? productName, Value? amount}) { return ProductArrivalPackageNewLinesCompanion( id: id ?? this.id, productArrivalPackageId: productArrivalPackageId ?? this.productArrivalPackageId, productId: productId ?? this.productId, - productName: productName ?? this.productName, amount: amount ?? this.amount, ); } @@ -2800,9 +3038,6 @@ class ProductArrivalPackageNewLinesCompanion if (productId.present) { map['product_id'] = Variable(productId.value); } - if (productName.present) { - map['product_name'] = Variable(productName.value); - } if (amount.present) { map['amount'] = Variable(amount.value); } @@ -2815,7 +3050,6 @@ class ProductArrivalPackageNewLinesCompanion ..write('id: $id, ') ..write('productArrivalPackageId: $productArrivalPackageId, ') ..write('productId: $productId, ') - ..write('productName: $productName, ') ..write('amount: $amount') ..write(')')) .toString(); @@ -2850,13 +3084,9 @@ class $ProductArrivalPackageNewLinesTable extends ProductArrivalPackageNewLines @override late final GeneratedColumn productId = GeneratedColumn( 'product_id', aliasedName, false, - type: const IntType(), requiredDuringInsert: true); - final VerificationMeta _productNameMeta = - const VerificationMeta('productName'); - @override - late final GeneratedColumn productName = GeneratedColumn( - 'product_name', aliasedName, false, - type: const StringType(), requiredDuringInsert: true); + type: const IntType(), + requiredDuringInsert: true, + defaultConstraints: 'REFERENCES products (id) ON DELETE CASCADE'); final VerificationMeta _amountMeta = const VerificationMeta('amount'); @override late final GeneratedColumn amount = GeneratedColumn( @@ -2864,7 +3094,7 @@ class $ProductArrivalPackageNewLinesTable extends ProductArrivalPackageNewLines type: const IntType(), requiredDuringInsert: true); @override List get $columns => - [id, productArrivalPackageId, productId, productName, amount]; + [id, productArrivalPackageId, productId, amount]; @override String get aliasedName => _alias ?? 'product_arrival_package_new_lines'; @override @@ -2893,14 +3123,6 @@ class $ProductArrivalPackageNewLinesTable extends ProductArrivalPackageNewLines } else if (isInserting) { context.missing(_productIdMeta); } - if (data.containsKey('product_name')) { - context.handle( - _productNameMeta, - productName.isAcceptableOrUnknown( - data['product_name']!, _productNameMeta)); - } else if (isInserting) { - context.missing(_productNameMeta); - } if (data.containsKey('amount')) { context.handle(_amountMeta, amount.isAcceptableOrUnknown(data['amount']!, _amountMeta)); @@ -2930,7 +3152,6 @@ class ProductArrivalPackageNewCell extends DataClass final int id; final int productArrivalPackageId; final int productId; - final String productName; final int storageCellId; final String storageCellName; final int amount; @@ -2938,7 +3159,6 @@ class ProductArrivalPackageNewCell extends DataClass {required this.id, required this.productArrivalPackageId, required this.productId, - required this.productName, required this.storageCellId, required this.storageCellName, required this.amount}); @@ -2952,8 +3172,6 @@ class ProductArrivalPackageNewCell extends DataClass data['${effectivePrefix}product_arrival_package_id'])!, productId: const IntType() .mapFromDatabaseResponse(data['${effectivePrefix}product_id'])!, - productName: const StringType() - .mapFromDatabaseResponse(data['${effectivePrefix}product_name'])!, storageCellId: const IntType() .mapFromDatabaseResponse(data['${effectivePrefix}storage_cell_id'])!, storageCellName: const StringType().mapFromDatabaseResponse( @@ -2968,7 +3186,6 @@ class ProductArrivalPackageNewCell extends DataClass map['id'] = Variable(id); map['product_arrival_package_id'] = Variable(productArrivalPackageId); map['product_id'] = Variable(productId); - map['product_name'] = Variable(productName); map['storage_cell_id'] = Variable(storageCellId); map['storage_cell_name'] = Variable(storageCellName); map['amount'] = Variable(amount); @@ -2980,7 +3197,6 @@ class ProductArrivalPackageNewCell extends DataClass id: Value(id), productArrivalPackageId: Value(productArrivalPackageId), productId: Value(productId), - productName: Value(productName), storageCellId: Value(storageCellId), storageCellName: Value(storageCellName), amount: Value(amount), @@ -2995,7 +3211,6 @@ class ProductArrivalPackageNewCell extends DataClass productArrivalPackageId: serializer.fromJson(json['productArrivalPackageId']), productId: serializer.fromJson(json['productId']), - productName: serializer.fromJson(json['productName']), storageCellId: serializer.fromJson(json['storageCellId']), storageCellName: serializer.fromJson(json['storageCellName']), amount: serializer.fromJson(json['amount']), @@ -3009,7 +3224,6 @@ class ProductArrivalPackageNewCell extends DataClass 'productArrivalPackageId': serializer.toJson(productArrivalPackageId), 'productId': serializer.toJson(productId), - 'productName': serializer.toJson(productName), 'storageCellId': serializer.toJson(storageCellId), 'storageCellName': serializer.toJson(storageCellName), 'amount': serializer.toJson(amount), @@ -3020,7 +3234,6 @@ class ProductArrivalPackageNewCell extends DataClass {int? id, int? productArrivalPackageId, int? productId, - String? productName, int? storageCellId, String? storageCellName, int? amount}) => @@ -3029,7 +3242,6 @@ class ProductArrivalPackageNewCell extends DataClass productArrivalPackageId: productArrivalPackageId ?? this.productArrivalPackageId, productId: productId ?? this.productId, - productName: productName ?? this.productName, storageCellId: storageCellId ?? this.storageCellId, storageCellName: storageCellName ?? this.storageCellName, amount: amount ?? this.amount, @@ -3040,7 +3252,6 @@ class ProductArrivalPackageNewCell extends DataClass ..write('id: $id, ') ..write('productArrivalPackageId: $productArrivalPackageId, ') ..write('productId: $productId, ') - ..write('productName: $productName, ') ..write('storageCellId: $storageCellId, ') ..write('storageCellName: $storageCellName, ') ..write('amount: $amount') @@ -3050,7 +3261,7 @@ class ProductArrivalPackageNewCell extends DataClass @override int get hashCode => Object.hash(id, productArrivalPackageId, productId, - productName, storageCellId, storageCellName, amount); + storageCellId, storageCellName, amount); @override bool operator ==(Object other) => identical(this, other) || @@ -3058,7 +3269,6 @@ class ProductArrivalPackageNewCell extends DataClass other.id == this.id && other.productArrivalPackageId == this.productArrivalPackageId && other.productId == this.productId && - other.productName == this.productName && other.storageCellId == this.storageCellId && other.storageCellName == this.storageCellName && other.amount == this.amount); @@ -3069,7 +3279,6 @@ class ProductArrivalPackageNewCellsCompanion final Value id; final Value productArrivalPackageId; final Value productId; - final Value productName; final Value storageCellId; final Value storageCellName; final Value amount; @@ -3077,7 +3286,6 @@ class ProductArrivalPackageNewCellsCompanion this.id = const Value.absent(), this.productArrivalPackageId = const Value.absent(), this.productId = const Value.absent(), - this.productName = const Value.absent(), this.storageCellId = const Value.absent(), this.storageCellName = const Value.absent(), this.amount = const Value.absent(), @@ -3086,13 +3294,11 @@ class ProductArrivalPackageNewCellsCompanion this.id = const Value.absent(), required int productArrivalPackageId, required int productId, - required String productName, required int storageCellId, required String storageCellName, required int amount, }) : productArrivalPackageId = Value(productArrivalPackageId), productId = Value(productId), - productName = Value(productName), storageCellId = Value(storageCellId), storageCellName = Value(storageCellName), amount = Value(amount); @@ -3100,7 +3306,6 @@ class ProductArrivalPackageNewCellsCompanion Expression? id, Expression? productArrivalPackageId, Expression? productId, - Expression? productName, Expression? storageCellId, Expression? storageCellName, Expression? amount, @@ -3110,7 +3315,6 @@ class ProductArrivalPackageNewCellsCompanion if (productArrivalPackageId != null) 'product_arrival_package_id': productArrivalPackageId, if (productId != null) 'product_id': productId, - if (productName != null) 'product_name': productName, if (storageCellId != null) 'storage_cell_id': storageCellId, if (storageCellName != null) 'storage_cell_name': storageCellName, if (amount != null) 'amount': amount, @@ -3121,7 +3325,6 @@ class ProductArrivalPackageNewCellsCompanion {Value? id, Value? productArrivalPackageId, Value? productId, - Value? productName, Value? storageCellId, Value? storageCellName, Value? amount}) { @@ -3130,7 +3333,6 @@ class ProductArrivalPackageNewCellsCompanion productArrivalPackageId: productArrivalPackageId ?? this.productArrivalPackageId, productId: productId ?? this.productId, - productName: productName ?? this.productName, storageCellId: storageCellId ?? this.storageCellId, storageCellName: storageCellName ?? this.storageCellName, amount: amount ?? this.amount, @@ -3150,9 +3352,6 @@ class ProductArrivalPackageNewCellsCompanion if (productId.present) { map['product_id'] = Variable(productId.value); } - if (productName.present) { - map['product_name'] = Variable(productName.value); - } if (storageCellId.present) { map['storage_cell_id'] = Variable(storageCellId.value); } @@ -3171,7 +3370,6 @@ class ProductArrivalPackageNewCellsCompanion ..write('id: $id, ') ..write('productArrivalPackageId: $productArrivalPackageId, ') ..write('productId: $productId, ') - ..write('productName: $productName, ') ..write('storageCellId: $storageCellId, ') ..write('storageCellName: $storageCellName, ') ..write('amount: $amount') @@ -3208,13 +3406,9 @@ class $ProductArrivalPackageNewCellsTable extends ProductArrivalPackageNewCells @override late final GeneratedColumn productId = GeneratedColumn( 'product_id', aliasedName, false, - type: const IntType(), requiredDuringInsert: true); - final VerificationMeta _productNameMeta = - const VerificationMeta('productName'); - @override - late final GeneratedColumn productName = GeneratedColumn( - 'product_name', aliasedName, false, - type: const StringType(), requiredDuringInsert: true); + type: const IntType(), + requiredDuringInsert: true, + defaultConstraints: 'REFERENCES products (id) ON DELETE CASCADE'); final VerificationMeta _storageCellIdMeta = const VerificationMeta('storageCellId'); @override @@ -3237,7 +3431,6 @@ class $ProductArrivalPackageNewCellsTable extends ProductArrivalPackageNewCells id, productArrivalPackageId, productId, - productName, storageCellId, storageCellName, amount @@ -3270,14 +3463,6 @@ class $ProductArrivalPackageNewCellsTable extends ProductArrivalPackageNewCells } else if (isInserting) { context.missing(_productIdMeta); } - if (data.containsKey('product_name')) { - context.handle( - _productNameMeta, - productName.isAcceptableOrUnknown( - data['product_name']!, _productNameMeta)); - } else if (isInserting) { - context.missing(_productNameMeta); - } if (data.containsKey('storage_cell_id')) { context.handle( _storageCellIdMeta, @@ -5304,6 +5489,7 @@ class $PrefsTable extends Prefs with TableInfo<$PrefsTable, Pref> { abstract class _$AppDataStore extends GeneratedDatabase { _$AppDataStore(QueryExecutor e) : super(SqlTypeSystem.defaultInstance, e); late final $UsersTable users = $UsersTable(this); + late final $ProductsTable products = $ProductsTable(this); late final $StoragesTable storages = $StoragesTable(this); late final $ProductArrivalsTable productArrivals = $ProductArrivalsTable(this); @@ -5340,6 +5526,7 @@ abstract class _$AppDataStore extends GeneratedDatabase { @override List get allSchemaEntities => [ users, + products, storages, productArrivals, productArrivalPackages, @@ -5371,6 +5558,7 @@ mixin _$ProductArrivalsDaoMixin on DatabaseAccessor { attachedDatabase.productArrivalPackages; $ProductArrivalUnloadPackagesTable get productArrivalUnloadPackages => attachedDatabase.productArrivalUnloadPackages; + $ProductsTable get products => attachedDatabase.products; $ProductArrivalPackageLinesTable get productArrivalPackageLines => attachedDatabase.productArrivalPackageLines; $ProductArrivalPackageTypesTable get productArrivalPackageTypes => diff --git a/lib/app/data/product_arrivals_dao.dart b/lib/app/data/product_arrivals_dao.dart index 23924b3..d0e6a4d 100644 --- a/lib/app/data/product_arrivals_dao.dart +++ b/lib/app/data/product_arrivals_dao.dart @@ -2,6 +2,7 @@ part of 'database.dart'; @DriftAccessor( tables: [ + Products, ProductArrivals, ProductArrivalPackages, ProductArrivalUnloadPackages, @@ -16,6 +17,13 @@ part of 'database.dart'; class ProductArrivalsDao extends DatabaseAccessor with _$ProductArrivalsDaoMixin { ProductArrivalsDao(AppDataStore db) : super(db); + Future loadProducts(List list) async { + await batch((batch) { + batch.deleteWhere(products, (row) => const Constant(true)); + batch.insertAll(products, list); + }); + } + Future loadProductArrivals(List list) async { await batch((batch) { batch.deleteWhere(productArrivals, (row) => const Constant(true)); @@ -51,20 +59,24 @@ class ProductArrivalsDao extends DatabaseAccessor with _$ProductAr }); } + Future addProduct(Product product) async { + await into(products).insert(product, mode: InsertMode.insertOrIgnore); + } + Future addProductArrivalNewPackage(ProductArrivalNewPackagesCompanion newPackage) async { - await into(productArrivalNewPackages).insert(newPackage); + await into(productArrivalNewPackages).insert(newPackage, mode: InsertMode.insertOrIgnore); } Future addProductArrivalPackageNewLine(ProductArrivalPackageNewLinesCompanion newLine) async { - await into(productArrivalPackageNewLines).insert(newLine); + await into(productArrivalPackageNewLines).insert(newLine, mode: InsertMode.insertOrIgnore); } Future addProductArrivalPackageNewCell(ProductArrivalPackageNewCellsCompanion newCell) async { - await into(productArrivalPackageNewCells).insert(newCell); + await into(productArrivalPackageNewCells).insert(newCell, mode: InsertMode.insertOrIgnore); } Future addProductArrivalNewUnloadPackage(ProductArrivalNewUnloadPackagesCompanion newUnloadPackage) async { - await into(productArrivalNewUnloadPackages).insert(newUnloadPackage); + await into(productArrivalNewUnloadPackages).insert(newUnloadPackage, mode: InsertMode.insertOrIgnore); } Future deleteProductArrivalNewPackage(ProductArrivalNewPackage newPackage) async { @@ -105,9 +117,9 @@ class ProductArrivalsDao extends DatabaseAccessor with _$ProductAr Future updateProductArrivalEx(ProductArrivalEx productArrivalEx) async { await (delete(productArrivals)..where((tbl) => tbl.id.equals(productArrivalEx.productArrival.id))).go(); await upsertProductArrival(productArrivalEx.productArrival.id, productArrivalEx.productArrival.toCompanion(false)); - await Future.forEach( + await Future.forEach( productArrivalEx.packages.map((e) => e.packageLines).expand((e) => e), - (e) => upsertProductArrivalPackageLine(e.id, e.toCompanion(false)) + (e) => upsertProductArrivalPackageLine(e.line.id, e.line.toCompanion(false)) ); await Future.forEach( productArrivalEx.packages, @@ -146,18 +158,34 @@ class ProductArrivalsDao extends DatabaseAccessor with _$ProductAr ).get(); } - Future> getProductArrivalPackageNewLines(int productArrivalPackageId) async { - return ( - select(productArrivalPackageNewLines) - ..where((e)=> e.productArrivalPackageId.equals(productArrivalPackageId)) - ).get(); + Future> getProductArrivalPackageNewLinesEx(int productArrivalPackageId) async { + final packageNewLinesQuery = select(productArrivalPackageNewLines) + .join([innerJoin(products, products.id.equalsExp(productArrivalPackageNewLines.productId))]) + ..where(productArrivalPackageNewLines.productArrivalPackageId.equals(productArrivalPackageId)) + ..orderBy([OrderingTerm(expression: products.name)]); + final packageNewLinesRes = await packageNewLinesQuery.get(); + + return packageNewLinesRes.map((packageLine) { + return ProductArrivalPackageNewLineEx( + packageLine.readTable(productArrivalPackageNewLines), + packageLine.readTable(products) + ); + }).toList(); } - Future> getProductArrivalPackageNewCells(int productArrivalPackageId) async { - return ( - select(productArrivalPackageNewCells) - ..where((e)=> e.productArrivalPackageId.equals(productArrivalPackageId)) - ).get(); + Future> getProductArrivalPackageNewCellsEx(int productArrivalPackageId) async { + final packageNewCellsQuery = select(productArrivalPackageNewCells) + .join([innerJoin(products, products.id.equalsExp(productArrivalPackageNewCells.productId))]) + ..where(productArrivalPackageNewCells.productArrivalPackageId.equals(productArrivalPackageId)) + ..orderBy([OrderingTerm(expression: products.name)]); + final packageNewCellsRes = await packageNewCellsQuery.get(); + + return packageNewCellsRes.map((packageLine) { + return ProductArrivalPackageNewCellEx( + packageLine.readTable(productArrivalPackageNewCells), + packageLine.readTable(products) + ); + }).toList(); } Future> getProductArrivalNewUnloadPackages(int productArrivalId) async { @@ -183,17 +211,25 @@ class ProductArrivalsDao extends DatabaseAccessor with _$ProductAr select(productArrivalUnloadPackages)..orderBy([(u) => OrderingTerm(expression: u.typeName)]) ).get(); final productArrivalPackageLinesRes = await ( - select(productArrivalPackageLines)..orderBy([(u) => OrderingTerm(expression: u.productName)]) + select(productArrivalPackageLines) + .join([innerJoin(products, products.id.equalsExp(productArrivalPackageLines.productId))]) + ..orderBy([OrderingTerm(expression: products.name)]) ).get(); return productArrivalsRes.map((productArrival) { final productArrivalPackages = productArrivalPackagesRes .where((e) => e.productArrivalId == productArrival.readTable(productArrivals).id) .map((e) { - return ProductArrivalPackageEx( - e, - productArrivalPackageLinesRes.where((line) => line.productArrivalPackageId == e.id).toList() - ); + final packageLinesRows = productArrivalPackageLinesRes + .where((line) => line.readTable(productArrivalPackageLines).productArrivalPackageId == e.id) + .map((line) { + return ProductArrivalPackageLineEx( + line.readTable(productArrivalPackageLines), + line.readTable(products) + ); + }).toList(); + + return ProductArrivalPackageEx(e, packageLinesRows); }) .toList(); final productArrivalUnloadPackages = productArrivalUnloadPackagesRes @@ -209,24 +245,31 @@ class ProductArrivalsDao extends DatabaseAccessor with _$ProductAr } Future getProductArrivalEx(int id) async { - return (await _getProductArrivalEx(productArrivals.id.equals(id)))!; + return (await _getProductArrivalEx(productArrivals.id.equals(id))).first; } Future getProductArrivalExByNumber(String number) async { - return _getProductArrivalEx(productArrivals.number.equals(number)); + return(await _getProductArrivalEx(productArrivals.number.equals(number))).firstOrNull; } Future getProductArrivalPackageEx(int id) async { - final productArrivalPackageRow = await (select(productArrivalPackages)..where((t) => t.id.equals(id))).getSingle(); - final productArrivalPackageLinesQuery = select(productArrivalPackageLines) - ..where((t) => t.productArrivalPackageId.equals(productArrivalPackageRow.id)) - ..orderBy([(u) => OrderingTerm(expression: u.productName)]); - final productArrivalPackageLinesRows = await productArrivalPackageLinesQuery.get(); + final packageRow = await (select(productArrivalPackages)..where((t) => t.id.equals(id))).getSingle(); + final packageLinesQuery = select(productArrivalPackageLines) + .join([innerJoin(products, products.id.equalsExp(productArrivalPackageLines.productId))]) + ..where(productArrivalPackageLines.productArrivalPackageId.equals(packageRow.id)) + ..orderBy([OrderingTerm(expression: products.name)]); + final packageLinesRes = await packageLinesQuery.get(); + final packageLinesRows = packageLinesRes.map((packageLine) { + return ProductArrivalPackageLineEx( + packageLine.readTable(productArrivalPackageLines), + packageLine.readTable(products) + ); + }).toList(); - return ProductArrivalPackageEx(productArrivalPackageRow, productArrivalPackageLinesRows); + return ProductArrivalPackageEx(packageRow, packageLinesRows); } - Future _getProductArrivalEx(Expression whereExp) async { + Future> _getProductArrivalEx(Expression whereExp) async { final productArrivalsQuery = select(productArrivals) .join([innerJoin(storages, storages.id.equalsExp(productArrivals.storageId))]) ..orderBy([ @@ -234,33 +277,48 @@ class ProductArrivalsDao extends DatabaseAccessor with _$ProductAr OrderingTerm(expression: productArrivals.arrivalDate) ]) ..where(whereExp); - final productArrivalRow = await productArrivalsQuery.getSingleOrNull(); + final productArrivalRows = await productArrivalsQuery.get(); - if (productArrivalRow == null) return null; - - final id = productArrivalRow.readTable(productArrivals).id; final productArrivalPackagesQuery = select(productArrivalPackages) - ..where((t) => t.productArrivalId.equals(id)) + ..where((t) => t.productArrivalId.isIn(productArrivalRows.map((e) => e.readTable(productArrivals).id))) ..orderBy([(u) => OrderingTerm(expression: u.id)]); - final productArrivalPackagesRows = await productArrivalPackagesQuery.get(); + final productArrivalPackagesRes = await productArrivalPackagesQuery.get(); final productArrivalUnloadPackagesQuery = select(productArrivalUnloadPackages) - ..where((t) => t.productArrivalId.equals(id)) + ..where((t) => t.productArrivalId.isIn(productArrivalRows.map((e) => e.readTable(productArrivals).id))) ..orderBy([(u) => OrderingTerm(expression: u.typeName)]); final productArrivalUnloadPackagesRows = await productArrivalUnloadPackagesQuery.get(); final productArrivalPackageLinesQuery = select(productArrivalPackageLines) - ..where((t) => t.productArrivalPackageId.isIn(productArrivalPackagesRows.map((e) => e.id))) - ..orderBy([(u) => OrderingTerm(expression: u.productName)]); - final productArrivalPackageLinesRows = await productArrivalPackageLinesQuery.get(); - - return ProductArrivalEx( - productArrivalRow.readTable(productArrivals), - productArrivalRow.readTable(storages), - productArrivalPackagesRows.map((e) => ProductArrivalPackageEx( - e, - productArrivalPackageLinesRows.where((line) => line.productArrivalPackageId == e.id).toList() - )).toList(), - productArrivalUnloadPackagesRows - ); + .join([innerJoin(products, products.id.equalsExp(productArrivalPackageLines.productId))]) + ..where(productArrivalPackageLines.productArrivalPackageId.isIn(productArrivalPackagesRes.map((e) => e.id))) + ..orderBy([OrderingTerm(expression: products.name)]); + final productArrivalPackageLinesRes = await productArrivalPackageLinesQuery.get(); + final productArrivalPackageLinesRows = productArrivalPackageLinesRes.map((packageLine) { + return ProductArrivalPackageLineEx( + packageLine.readTable(productArrivalPackageLines), + packageLine.readTable(products) + ); + }).toList(); + final productArrivalPackagesRows = productArrivalPackagesRes.map((e) => ProductArrivalPackageEx( + e, + productArrivalPackageLinesRows.where((lineEx) => lineEx.line.productArrivalPackageId == e.id).toList() + )).toList(); + + return productArrivalRows.map((productArrivalRow) { + final productArrival = productArrivalRow.readTable(productArrivals); + final packages = productArrivalPackagesRows + .where((packageEx) => packageEx.package.productArrivalId == productArrival.id) + .toList(); + final unloadPackages = productArrivalUnloadPackagesRows + .where((unloadPackage) => unloadPackage.productArrivalId == productArrival.id) + .toList(); + + return ProductArrivalEx( + productArrival, + productArrivalRow.readTable(storages), + packages, + unloadPackages + ); + }).toList(); } } @@ -275,7 +333,28 @@ class ProductArrivalEx { class ProductArrivalPackageEx { final ProductArrivalPackage package; - final List packageLines; + final List packageLines; ProductArrivalPackageEx(this.package, this.packageLines); } + +class ProductArrivalPackageLineEx { + ProductArrivalPackageLine line; + Product product; + + ProductArrivalPackageLineEx(this.line, this.product); +} + +class ProductArrivalPackageNewLineEx { + ProductArrivalPackageNewLine line; + Product product; + + ProductArrivalPackageNewLineEx(this.line, this.product); +} + +class ProductArrivalPackageNewCellEx { + final ProductArrivalPackageNewCell newCell; + final Product product; + + ProductArrivalPackageNewCellEx(this.newCell, this.product); +} diff --git a/lib/app/data/schema.dart b/lib/app/data/schema.dart index 678632a..cd36bff 100644 --- a/lib/app/data/schema.dart +++ b/lib/app/data/schema.dart @@ -21,6 +21,14 @@ class ApiCredentials extends Table { TextColumn get url => text()(); } +class Products extends Table { + IntColumn get id => integer().autoIncrement()(); + TextColumn get name => text()(); + TextColumn get article => text().nullable()(); + TextColumn get barcodeCode => text().nullable()(); + TextColumn get barcodeType => text().nullable()(); +} + class ProductArrivals extends Table { IntColumn get id => integer().autoIncrement()(); DateTimeColumn get arrivalDate => dateTime()(); @@ -64,8 +72,8 @@ class ProductArrivalPackageLines extends Table { IntColumn get id => integer().autoIncrement()(); IntColumn get productArrivalPackageId => integer() .references(ProductArrivalPackages, #id, onDelete: KeyAction.cascade)(); - IntColumn get productId => integer()(); - TextColumn get productName => text()(); + IntColumn get productId => integer() + .references(Products, #id, onDelete: KeyAction.cascade)(); IntColumn get amount => integer()(); } @@ -73,8 +81,8 @@ class ProductArrivalPackageNewLines extends Table { IntColumn get id => integer().autoIncrement()(); IntColumn get productArrivalPackageId => integer() .references(ProductArrivalPackages, #id, onDelete: KeyAction.cascade)(); - IntColumn get productId => integer()(); - TextColumn get productName => text()(); + IntColumn get productId => integer() + .references(Products, #id, onDelete: KeyAction.cascade)(); IntColumn get amount => integer()(); } @@ -82,8 +90,8 @@ class ProductArrivalPackageNewCells extends Table { IntColumn get id => integer().autoIncrement()(); IntColumn get productArrivalPackageId => integer() .references(ProductArrivalPackages, #id, onDelete: KeyAction.cascade)(); - IntColumn get productId => integer()(); - TextColumn get productName => text()(); + IntColumn get productId => integer() + .references(Products, #id, onDelete: KeyAction.cascade)(); IntColumn get storageCellId => integer()(); TextColumn get storageCellName => text()(); IntColumn get amount => integer()(); diff --git a/lib/app/data/storages_dao.dart b/lib/app/data/storages_dao.dart index 8ee191a..ae6fa44 100644 --- a/lib/app/data/storages_dao.dart +++ b/lib/app/data/storages_dao.dart @@ -11,7 +11,7 @@ class StoragesDao extends DatabaseAccessor with _$StoragesDaoMixin } Future addStorage(Storage storage) async { - await into(storages).insert(storage, mode: InsertMode.insertOrReplace); + await into(storages).insert(storage, mode: InsertMode.insertOrIgnore); } Future loadStorages(List storageList) async { diff --git a/lib/app/entities/api_product.dart b/lib/app/entities/api_product.dart index f9765e8..0cd7965 100644 --- a/lib/app/entities/api_product.dart +++ b/lib/app/entities/api_product.dart @@ -3,22 +3,44 @@ part of 'entities.dart'; class ApiProduct extends Equatable { final int id; final String name; + final String? article; + final String? barcodeCode; + final String? barcodeType; const ApiProduct({ required this.id, - required this.name + required this.name, + this.article, + this.barcodeCode, + this.barcodeType }); factory ApiProduct.fromJson(dynamic json) { return ApiProduct( id: json['id'], - name: json['name'] + name: json['name'], + article: json['article'], + barcodeCode: json['barcodeCode'], + barcodeType: json['barcodeType'] + ); + } + + Product toDatabaseEnt() { + return Product( + id: id, + name: name, + article: article, + barcodeCode: barcodeCode, + barcodeType: barcodeType ); } @override List get props => [ id, - name + name, + article, + barcodeCode, + barcodeType ]; } diff --git a/lib/app/entities/api_product_arrival.dart b/lib/app/entities/api_product_arrival.dart index 403d518..abcf5eb 100644 --- a/lib/app/entities/api_product_arrival.dart +++ b/lib/app/entities/api_product_arrival.dart @@ -76,13 +76,23 @@ class ApiProductArrival extends Equatable { acceptEnd: e.acceptEnd, placed: e.placed ); - final lines = e.lines.map((line) => ProductArrivalPackageLine( - id: line.id, - productArrivalPackageId: e.id, - productId: line.productId, - productName: line.productName, - amount: line.amount - )).toList(); + final lines = e.lines.map((line) { + final product = Product( + id: line.product.id, + name: line.product.name, + article: line.product.article, + barcodeCode: line.product.barcodeCode, + barcodeType: line.product.barcodeType, + ); + final productArrivalPackageLine = ProductArrivalPackageLine( + id: line.id, + productArrivalPackageId: e.id, + productId: product.id, + amount: line.amount + ); + + return ProductArrivalPackageLineEx(productArrivalPackageLine, product); + }).toList(); return ProductArrivalPackageEx(productArrivalPackage, lines); }).toList(); diff --git a/lib/app/entities/api_product_arrival_package_line.dart b/lib/app/entities/api_product_arrival_package_line.dart index ec7b77c..efb6541 100644 --- a/lib/app/entities/api_product_arrival_package_line.dart +++ b/lib/app/entities/api_product_arrival_package_line.dart @@ -2,31 +2,27 @@ part of 'entities.dart'; class ApiProductArrivalPackageLine extends Equatable { final int id; - final int productId; - final String productName; + final Product product; final int amount; const ApiProductArrivalPackageLine({ required this.id, - required this.productId, - required this.productName, - required this.amount + required this.amount, + required this.product }); factory ApiProductArrivalPackageLine.fromJson(dynamic json) { return ApiProductArrivalPackageLine( id: json['id'], - productId: json['productId'], - productName: json['productName'], - amount: json['amount'] + amount: json['amount'], + product: Product.fromJson(json['product']) ); } @override List get props => [ id, - productId, - productName, - amount + amount, + product ]; } diff --git a/lib/app/labels/product_arrival_packages_label.dart b/lib/app/labels/product_arrival_packages_label.dart new file mode 100644 index 0000000..0471e5a --- /dev/null +++ b/lib/app/labels/product_arrival_packages_label.dart @@ -0,0 +1,38 @@ +import '/app/data/database.dart'; +import '/app/services/printer.dart'; +import '/app/utils/format.dart'; + +class ProductArrivalPackagesLabel { + final ProductArrivalEx productArrivalEx; + final Printer _printer = Printer(); + + ProductArrivalPackagesLabel({ + required this.productArrivalEx + }); + + Future print({ + required Function onError, + int amount = 1 + }) async { + String labelCommand = productArrivalEx.packages.map((e) { + String formattedDate = Format.dateStr(productArrivalEx.productArrival.arrivalDate); + String command = ''' + SIZE 2.8,4.61 + GAP 0.18,0 + CODEPAGE UTF-8 + COUNTRY 061 + DIRECTION 0 + CLS + QRCODE 130,100,Q,10,A,0,M2,"${e.package.qr}" + TEXT 300,460,"5",0,1,1,2,"${e.package.number}" + TEXT 300,530,"3",0,1,1,2,"Приемка #${productArrivalEx.productArrival.number} от $formattedDate" + TEXT 300,560,"3",0,1,1,2,"Всего мест: ${productArrivalEx.packages.length}" + PRINT 1,$amount + '''; + + return command; + }).toList().join('\n'); + + _printer.printLabel(labelCommand, onError: onError); + } +} diff --git a/lib/app/labels/product_label.dart b/lib/app/labels/product_label.dart new file mode 100644 index 0000000..182f47d --- /dev/null +++ b/lib/app/labels/product_label.dart @@ -0,0 +1,53 @@ +import '/app/data/database.dart'; +import '/app/services/printer.dart'; +import '/app/utils/format.dart'; + +class ProductLabel { + final Product product; + final User user; + final Printer _printer = Printer(); + + ProductLabel({ + required this.product, + required this.user + }); + + Future print({ + required Function onError, + int amount = 1 + }) async { + String? barcodeType; + + switch (product.barcodeType) { + case 'code128': + barcodeType = '128'; + break; + case 'ean13': + barcodeType = 'EAN13'; + break; + } + + String formattedDate = Format.dateTimeStr(DateTime.now()); + String wrappedName = Format.wrapLine(product.name, 35).asMap().entries.map((entry) { + return 'TEXT 10,${80 + 30 * entry.key},"3",0,1,1,"${entry.value}"'; + }).join('\n'); + String article = product.article ?? ''; + int articleLen = ((Printer.kPaperWidth - (100 * article.length/8))/2).ceil(); + + String labelCommand = ''' + SIZE 2.8,4.61 + GAP 0.18,0 + CODEPAGE UTF-8 + COUNTRY 061 + DIRECTION 0 + CLS + $wrappedName + TEXT ${articleLen < 0 ? 0 : articleLen},400,"0",0,10,10,"$article" + BARCODE 50,500,"$barcodeType",200,2,0,5,2,"${product.barcodeCode}" + TEXT 10,900,"2",0,1,1,"$formattedDate ${user.username}" + PRINT 1,$amount + '''; + + _printer.printLabel(labelCommand, onError: onError); + } +} diff --git a/lib/app/pages/info/info_view_model.dart b/lib/app/pages/info/info_view_model.dart index e43cb6d..ea61bbd 100644 --- a/lib/app/pages/info/info_view_model.dart +++ b/lib/app/pages/info/info_view_model.dart @@ -51,11 +51,14 @@ class InfoViewModel extends PageViewModel { List productArrivalExs = data.productArrivals.map((e) => e.toDatabaseEnt()).toList(); List orderEx = data.orders.map((e) => e.toDatabaseEnt()).toList(); List productArrivals = productArrivalExs.map((e) => e.productArrival).toList(); - List productArrivalPackageEx = productArrivalExs + List productArrivalPackagesEx = productArrivalExs .map((e) => e.packages).expand((e) => e).toList(); - List productArrivalPackages = productArrivalPackageEx.map((e) => e.package).toList(); - List productArrivalPackageLines = productArrivalPackageEx + List productArrivalPackages = productArrivalPackagesEx.map((e) => e.package).toList(); + List productArrivalPackageLinesEx = productArrivalPackagesEx .map((e) => e.packageLines).expand((e) => e).toList(); + List productArrivalPackageLines = productArrivalPackageLinesEx + .map((e) => e.line).toList(); + List products = productArrivalPackageLinesEx.map((e) => e.product).toList(); List productArrivalUnloadPackages = productArrivalExs .map((e) => e.unloadPackages).expand((e) => e).toList(); List productArrivalPackageTypes = data.productArrivalPackageTypes @@ -72,6 +75,7 @@ class InfoViewModel extends PageViewModel { await dataStore.ordersDao.loadOrders(orders); await dataStore.ordersDao.loadOrderLines(orderLines); await dataStore.storagesDao.loadStorages(storages); + await dataStore.productArrivalsDao.loadProducts(products); await dataStore.productArrivalsDao.loadProductArrivals(productArrivals); await dataStore.productArrivalsDao.loadProductArrivalPackages(productArrivalPackages); await dataStore.productArrivalsDao.loadProductArrivalUnloadPackages(productArrivalUnloadPackages); diff --git a/lib/app/pages/product_arrivals/product_arrival/package/new_line/new_line_page.dart b/lib/app/pages/product_arrivals/product_arrival/package/new_line/new_line_page.dart index ba5bfa1..f38ddc0 100644 --- a/lib/app/pages/product_arrivals/product_arrival/package/new_line/new_line_page.dart +++ b/lib/app/pages/product_arrivals/product_arrival/package/new_line/new_line_page.dart @@ -86,7 +86,7 @@ class NewLineViewState extends State<_NewLineView> { ); }, suggestionsCallback: (String pattern) => vm.findProductsByName(pattern), - itemBuilder: (BuildContext ctx, ApiProduct suggestion) { + itemBuilder: (BuildContext ctx, Product suggestion) { return ListTile( isThreeLine: false, title: Text(suggestion.name, style: Theme.of(context).textTheme.caption) diff --git a/lib/app/pages/product_arrivals/product_arrival/package/new_line/new_line_state.dart b/lib/app/pages/product_arrivals/product_arrival/package/new_line/new_line_state.dart index 7c4adfb..720a523 100644 --- a/lib/app/pages/product_arrivals/product_arrival/package/new_line/new_line_state.dart +++ b/lib/app/pages/product_arrivals/product_arrival/package/new_line/new_line_state.dart @@ -22,14 +22,14 @@ class NewLineState { final NewLineStateStatus status; final String message; final ProductArrivalPackageEx packageEx; - final ApiProduct? product; + final Product? product; final int? amount; NewLineState copyWith({ NewLineStateStatus? status, ProductArrivalPackageEx? packageEx, String? message, - Optional? product, + Optional? product, Optional? amount }) { return NewLineState( diff --git a/lib/app/pages/product_arrivals/product_arrival/package/new_line/new_line_view_model.dart b/lib/app/pages/product_arrivals/product_arrival/package/new_line/new_line_view_model.dart index c3ff46f..9f09904 100644 --- a/lib/app/pages/product_arrivals/product_arrival/package/new_line/new_line_view_model.dart +++ b/lib/app/pages/product_arrivals/product_arrival/package/new_line/new_line_view_model.dart @@ -10,7 +10,7 @@ class NewLineViewModel extends PageViewModel { @override Future loadData() async {} - Future> findProductsByName(String name) async { + Future> findProductsByName(String name) async { try { return await _findProduct(name: name); } on AppError catch(e) { @@ -24,7 +24,7 @@ class NewLineViewModel extends PageViewModel { emit(state.copyWith(status: NewLineStateStatus.inProgress)); try { - List products = await _findProduct(code: code); + List products = await _findProduct(code: code); if (products.isEmpty) { emit(state.copyWith(status: NewLineStateStatus.failure, message: 'Не найден товар')); @@ -37,7 +37,7 @@ class NewLineViewModel extends PageViewModel { } } - void setProduct(ApiProduct product) { + void setProduct(Product product) { emit(state.copyWith( status: NewLineStateStatus.setProduct, product: Optional.fromNullable(product)) @@ -64,7 +64,6 @@ class NewLineViewModel extends PageViewModel { ProductArrivalPackageNewLinesCompanion line = ProductArrivalPackageNewLinesCompanion( productArrivalPackageId: Value(state.packageEx.package.id), - productName: Value(state.product!.name), productId: Value(state.product!.id), amount: Value(state.amount!) ); @@ -74,9 +73,17 @@ class NewLineViewModel extends PageViewModel { emit(state.copyWith(status: NewLineStateStatus.lineAdded)); } - Future> _findProduct({String? code, String? name}) async { + Future> _findProduct({String? code, String? name}) async { try { - return await Api(dataStore: app.dataStore).productArrivalFindProduct(code: code, name: name); + List apiProducts = await Api(dataStore: app.dataStore) + .productArrivalFindProduct(code: code, name: name); + List products = apiProducts.map((e) => e.toDatabaseEnt()).toList(); + + await app.dataStore.transaction(() async { + await Future.wait(products.map((e) => app.dataStore.productArrivalsDao.addProduct(e))); + }); + + return products; } on ApiException catch(e) { throw AppError(e.errorMsg); } catch(e, trace) { diff --git a/lib/app/pages/product_arrivals/product_arrival/package/package_page.dart b/lib/app/pages/product_arrivals/product_arrival/package/package_page.dart index 227a94a..bbad4a9 100644 --- a/lib/app/pages/product_arrivals/product_arrival/package/package_page.dart +++ b/lib/app/pages/product_arrivals/product_arrival/package/package_page.dart @@ -8,6 +8,7 @@ import '/app/constants/strings.dart'; import '/app/constants/style.dart'; import '/app/data/database.dart'; import '/app/entities/entities.dart'; +import '/app/labels/product_label.dart'; import '/app/pages/shared/page_view_model.dart'; import '/app/services/api.dart'; import '/app/widgets/widgets.dart'; @@ -54,6 +55,50 @@ class _PackageViewState extends State<_PackageView> { ); } + Future showProductLabelPrintDialog(Product product) async { + PackageViewModel vm = context.read(); + int? amount; + + bool result = await showDialog( + context: context, + builder: (context) { + return StatefulBuilder( + builder: (context, setState) { + return AlertDialog( + alignment: Alignment.topCenter, + title: const Text('Укажите кол-во этикеток'), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TextField( + autofocus: true, + keyboardType: TextInputType.number, + onChanged: (newAmount) => setState(() => amount = int.tryParse(newAmount)), + decoration: const InputDecoration(labelText: 'Кол-во'), + ) + ], + ), + actions: [ + TextButton( + onPressed: amount != null && amount! > 0 ? () => Navigator.of(context).pop(true) : null, + child: const Text('Подтвердить') + ), + TextButton( + onPressed: () => Navigator.of(context).pop(false), + child: const Text('Отменить') + ) + ] + ); + } + ); + } + ) ?? false; + + if (!result) return; + + await vm.printProductLabel(product, amount!); + } + @override Widget build(BuildContext context) { return BlocConsumer( @@ -64,7 +109,7 @@ class _PackageViewState extends State<_PackageView> { return Scaffold( appBar: AppBar( title: Text('${package.typeName} ${package.number}. Приемка'), - actions: !state.inProgress || state.newLines.isEmpty ? + actions: !state.inProgress || state.newLineExList.isEmpty ? [] : [IconButton(icon: const Icon(Icons.check), onPressed: vm.endAccept)] ), @@ -96,7 +141,7 @@ class _PackageViewState extends State<_PackageView> { List lineWidgets = vm.state.packageEx.packageLines.map( (packageEx) => _productArrivalPackageLineTile(context, packageEx) ).toList(); - List newLineWidgets = vm.state.newLines.map( + List newLineWidgets = vm.state.newLineExList.map( (packageEx) => _productArrivalPackageNewLineTile(context, packageEx) ).toList(); @@ -110,23 +155,37 @@ class _PackageViewState extends State<_PackageView> { ); } - Widget _productArrivalPackageLineTile(BuildContext context, ProductArrivalPackageLine line) { + Widget _productArrivalPackageLineTile(BuildContext context, ProductArrivalPackageLineEx lineEx) { return ListTile( - title: Text(line.productName, style: Style.listTileText), - trailing: Text(line.amount.toString(), style: Style.listTileText) + leading: IconButton( + icon: const Icon(Icons.print_sharp), + onPressed: () => showProductLabelPrintDialog(lineEx.product), + tooltip: 'Распечатать этикетку', + constraints: const BoxConstraints(), + padding: const EdgeInsets.only(left: 8) + ), + title: Text(lineEx.product.name, style: Style.listTileText), + trailing: Text(lineEx.line.amount.toString(), style: Style.listTileText) ); } - Widget _productArrivalPackageNewLineTile(BuildContext context, ProductArrivalPackageNewLine newLine) { + Widget _productArrivalPackageNewLineTile(BuildContext context, ProductArrivalPackageNewLineEx newLineEx) { PackageViewModel vm = context.read(); return Dismissible( - key: Key(newLine.hashCode.toString()), + key: Key(newLineEx.hashCode.toString()), background: Container(color: Colors.red[500]), - onDismissed: (direction) => vm.deleteProductArrivalPackageNewLine(newLine), + onDismissed: (direction) => vm.deleteProductArrivalPackageNewLine(newLineEx), child: ListTile( - title: Text(newLine.productName, style: Style.listTileText), - trailing: Text(newLine.amount.toString(), style: Style.listTileText) + leading: IconButton( + icon: const Icon(Icons.print_sharp), + onPressed: () => showProductLabelPrintDialog(newLineEx.product), + tooltip: 'Распечатать этикетку', + constraints: const BoxConstraints(), + padding: const EdgeInsets.only(left: 8) + ), + title: Text(newLineEx.product.name, style: Style.listTileText), + trailing: Text(newLineEx.line.amount.toString(), style: Style.listTileText) ) ); } diff --git a/lib/app/pages/product_arrivals/product_arrival/package/package_state.dart b/lib/app/pages/product_arrivals/product_arrival/package/package_state.dart index 19157a1..877d4a9 100644 --- a/lib/app/pages/product_arrivals/product_arrival/package/package_state.dart +++ b/lib/app/pages/product_arrivals/product_arrival/package/package_state.dart @@ -13,13 +13,15 @@ class PackageState { this.status = PackageStateStatus.initial, required this.packageEx, this.message = '', - this.newLines = const [] + this.newLineExList = const [], + this.user }); final PackageStateStatus status; final ProductArrivalPackageEx packageEx; final String message; - final List newLines; + final List newLineExList; + final User? user; bool get inProgress => packageEx.package.acceptStart != null && packageEx.package.acceptEnd == null; @@ -27,13 +29,15 @@ class PackageState { PackageStateStatus? status, ProductArrivalPackageEx? packageEx, String? message, - List? newLines + List? newLineExList, + User? user }) { return PackageState( status: status ?? this.status, packageEx: packageEx ?? this.packageEx, message: message ?? this.message, - newLines: newLines ?? this.newLines + newLineExList: newLineExList ?? this.newLineExList, + user: user ?? this.user ); } } diff --git a/lib/app/pages/product_arrivals/product_arrival/package/package_view_model.dart b/lib/app/pages/product_arrivals/product_arrival/package/package_view_model.dart index fa02d60..1ce01a6 100644 --- a/lib/app/pages/product_arrivals/product_arrival/package/package_view_model.dart +++ b/lib/app/pages/product_arrivals/product_arrival/package/package_view_model.dart @@ -21,16 +21,24 @@ class PackageViewModel extends PageViewModel { emit(state.copyWith( status: PackageStateStatus.dataLoaded, + user: await app.dataStore.usersDao.getUser(), packageEx: await app.dataStore.productArrivalsDao.getProductArrivalPackageEx(productArrivalPackageId), - newLines: await app.dataStore.productArrivalsDao.getProductArrivalPackageNewLines(productArrivalPackageId) + newLineExList: await app.dataStore.productArrivalsDao.getProductArrivalPackageNewLinesEx(productArrivalPackageId) )); } + Future printProductLabel(Product product, int amount) async { + ProductLabel(product: product, user: state.user!).print( + amount: amount, + onError: (String error) => emit(state.copyWith(status: PackageStateStatus.failure, message: error)) + ); + } + Future endAccept() async { emit(state.copyWith(status: PackageStateStatus.inProgress)); try { - await _endAccept(state.packageEx, state.newLines); + await _endAccept(state.packageEx, state.newLineExList); emit(state.copyWith(status: PackageStateStatus.success, message: 'Отмечено завершение разгрузки')); } on AppError catch(e) { @@ -38,15 +46,15 @@ class PackageViewModel extends PageViewModel { } } - Future deleteProductArrivalPackageNewLine(ProductArrivalPackageNewLine packageNewLine) async { - await app.dataStore.productArrivalsDao.deleteProductArrivalPackageNewLine(packageNewLine); + Future deleteProductArrivalPackageNewLine(ProductArrivalPackageNewLineEx packageNewLineEx) async { + await app.dataStore.productArrivalsDao.deleteProductArrivalPackageNewLine(packageNewLineEx.line); } - Future _endAccept(ProductArrivalPackageEx packageEx, List newLines) async { + Future _endAccept(ProductArrivalPackageEx packageEx, List newLineExList) async { try { ApiProductArrival newApiProductArrival = await Api(dataStore: app.dataStore).productArrivalsFinishPackageAccept( id: packageEx.package.id, - lines: newLines.map((e) => { 'productId': e.productId, 'amount': e.amount }).toList() + lines: newLineExList.map((e) => { 'productId': e.product.id, 'amount': e.line.amount }).toList() ); await app.dataStore.productArrivalsDao.clearProductArrivalPackageNewLines(); diff --git a/lib/app/pages/product_arrivals/product_arrival/package_cells/new_package_cell/new_package_cell_page.dart b/lib/app/pages/product_arrivals/product_arrival/package_cells/new_package_cell/new_package_cell_page.dart index 40c7962..8220056 100644 --- a/lib/app/pages/product_arrivals/product_arrival/package_cells/new_package_cell/new_package_cell_page.dart +++ b/lib/app/pages/product_arrivals/product_arrival/package_cells/new_package_cell/new_package_cell_page.dart @@ -77,11 +77,11 @@ class NewPackageCellViewState extends State<_NewPackageCellView> { suffixIcon: IconButton(icon: const Icon(CupertinoIcons.barcode), onPressed: _onScan) ), value: vm.state.product, - items: vm.state.packageLineProducts.map((e) => DropdownMenuItem( + items: vm.state.packageLineProducts.map((e) => DropdownMenuItem( value: e, child: Text(e.name, style: Style.listTileText.merge(theme.textTheme.labelMedium)) )).toList(), - onChanged: (ApiProduct? newVal) => newVal != null ? vm.setProduct(newVal) : null + onChanged: (Product? newVal) => newVal != null ? vm.setProduct(newVal) : null ), TextFormField( focusNode: amountFocus, diff --git a/lib/app/pages/product_arrivals/product_arrival/package_cells/new_package_cell/new_package_cell_state.dart b/lib/app/pages/product_arrivals/product_arrival/package_cells/new_package_cell/new_package_cell_state.dart index 7a739f9..da44f98 100644 --- a/lib/app/pages/product_arrivals/product_arrival/package_cells/new_package_cell/new_package_cell_state.dart +++ b/lib/app/pages/product_arrivals/product_arrival/package_cells/new_package_cell/new_package_cell_state.dart @@ -26,17 +26,17 @@ class NewPackageCellState { final String message; final ProductArrivalPackageEx packageEx; final ApiStorageCell storageCell; - final List packageLineProducts; - final ApiProduct? product; + final List packageLineProducts; + final Product? product; final int? amount; NewPackageCellState copyWith({ NewPackageCellStateStatus? status, ProductArrivalPackageEx? packageEx, ApiStorageCell? storageCell, - final List? packageLineProducts, + final List? packageLineProducts, String? message, - Optional? product, + Optional? product, Optional? amount }) { return NewPackageCellState( diff --git a/lib/app/pages/product_arrivals/product_arrival/package_cells/new_package_cell/new_package_cell_view_model.dart b/lib/app/pages/product_arrivals/product_arrival/package_cells/new_package_cell/new_package_cell_view_model.dart index c2b47e5..6bb7173 100644 --- a/lib/app/pages/product_arrivals/product_arrival/package_cells/new_package_cell/new_package_cell_view_model.dart +++ b/lib/app/pages/product_arrivals/product_arrival/package_cells/new_package_cell/new_package_cell_view_model.dart @@ -14,9 +14,7 @@ class NewPackageCellViewModel extends PageViewModel loadData() async { - List products = state.packageEx.packageLines.map( - (e) => ApiProduct(id: e.productId, name: e.productName) - ).toSet().toList(); + List products = state.packageEx.packageLines.map((e) => e.product).toSet().toList(); emit(state.copyWith(status: NewPackageCellStateStatus.dataLoaded, packageLineProducts: products)); } @@ -25,14 +23,14 @@ class NewPackageCellViewModel extends PageViewModel products = await _findProduct(code: code); + List products = await _findProduct(code: code); if (products.isEmpty) { emit(state.copyWith(status: NewPackageCellStateStatus.failure, message: 'Не найден товар')); return; } - ApiProduct product = products.first; + Product product = products.first; if (!state.packageLineProducts.contains(product)) { emit(state.copyWith(status: NewPackageCellStateStatus.failure, message: 'Товар не принимался')); @@ -45,7 +43,7 @@ class NewPackageCellViewModel extends PageViewModel> _findProduct({String? code, String? name}) async { + Future> _findProduct({String? code, String? name}) async { try { - return await Api(dataStore: app.dataStore).productArrivalFindProduct(code: code, name: name); + List apiProducts = await Api(dataStore: app.dataStore) + .productArrivalFindProduct(code: code, name: name); + List products = apiProducts.map((e) => e.toDatabaseEnt()).toList(); + + await app.dataStore.transaction(() async { + await Future.wait(products.map((e) => app.dataStore.productArrivalsDao.addProduct(e))); + }); + + return products; } on ApiException catch(e) { throw AppError(e.errorMsg); } catch(e, trace) { diff --git a/lib/app/pages/product_arrivals/product_arrival/package_cells/package_cells_page.dart b/lib/app/pages/product_arrivals/product_arrival/package_cells/package_cells_page.dart index 881d1c0..3ff9a53 100644 --- a/lib/app/pages/product_arrivals/product_arrival/package_cells/package_cells_page.dart +++ b/lib/app/pages/product_arrivals/product_arrival/package_cells/package_cells_page.dart @@ -10,6 +10,7 @@ import '/app/constants/strings.dart'; import '/app/constants/style.dart'; import '/app/data/database.dart'; import '/app/entities/entities.dart'; +import '/app/labels/product_label.dart'; import '/app/pages/shared/page_view_model.dart'; import '/app/services/api.dart'; import '/app/widgets/widgets.dart'; @@ -57,6 +58,50 @@ class PackageCellsViewState extends State<_PackageCellsView> { ).show(); } + Future showProductLabelPrintDialog(Product product) async { + PackageCellsViewModel vm = context.read(); + int? amount; + + bool result = await showDialog( + context: context, + builder: (context) { + return StatefulBuilder( + builder: (context, setState) { + return AlertDialog( + alignment: Alignment.topCenter, + title: const Text('Укажите кол-во этикеток'), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + TextField( + autofocus: true, + keyboardType: TextInputType.number, + onChanged: (newAmount) => setState(() => amount = int.tryParse(newAmount)), + decoration: const InputDecoration(labelText: 'Кол-во'), + ) + ], + ), + actions: [ + TextButton( + onPressed: amount != null && amount! > 0 ? () => Navigator.of(context).pop(true) : null, + child: const Text('Подтвердить') + ), + TextButton( + onPressed: () => Navigator.of(context).pop(false), + child: const Text('Отменить') + ) + ] + ); + } + ); + } + ) ?? false; + + if (!result) return; + + await vm.printProductLabel(product, amount!); + } + @override Widget build(BuildContext context) { return BlocConsumer( @@ -115,8 +160,8 @@ class PackageCellsViewState extends State<_PackageCellsView> { Widget _lineList(BuildContext context) { PackageCellsViewModel vm = context.read(); List storageCellWidgets = vm.state.storageCellNames.map(((storageCellName) { - List newCells = vm.state.newCells - .where((e) => e.storageCellName == storageCellName).toList(); + List newCells = vm.state.newCells + .where((e) => e.newCell.storageCellName == storageCellName).toList(); return ExpansionTile( title: Text(storageCellName, style: const TextStyle(fontSize: 14)), @@ -133,16 +178,23 @@ class PackageCellsViewState extends State<_PackageCellsView> { ); } - Widget _productArrivalPackageNewCellTile(BuildContext context, ProductArrivalPackageNewCell newCell) { + Widget _productArrivalPackageNewCellTile(BuildContext context, ProductArrivalPackageNewCellEx newCellEx) { PackageCellsViewModel vm = context.read(); return Dismissible( - key: Key(newCell.hashCode.toString()), + key: Key(newCellEx.hashCode.toString()), background: Container(color: Colors.red[500]), - onDismissed: (direction) => vm.deleteProductArrivalPackageNewCell(newCell), + onDismissed: (direction) => vm.deleteProductArrivalPackageNewCell(newCellEx), child: ListTile( - title: Text(newCell.productName, style: Style.listTileText), - trailing: Text(newCell.amount.toString(), style: Style.listTileText) + leading: IconButton( + icon: const Icon(Icons.print_sharp), + onPressed: () => showProductLabelPrintDialog(newCellEx.product), + tooltip: 'Распечатать места', + constraints: const BoxConstraints(), + padding: const EdgeInsets.only(left: 8) + ), + title: Text(newCellEx.product.name, style: Style.listTileText), + trailing: Text(newCellEx.newCell.amount.toString(), style: Style.listTileText) ) ); } diff --git a/lib/app/pages/product_arrivals/product_arrival/package_cells/package_cells_state.dart b/lib/app/pages/product_arrivals/product_arrival/package_cells/package_cells_state.dart index cefb9e7..0762720 100644 --- a/lib/app/pages/product_arrivals/product_arrival/package_cells/package_cells_state.dart +++ b/lib/app/pages/product_arrivals/product_arrival/package_cells/package_cells_state.dart @@ -16,15 +16,17 @@ class PackageCellsState { this.message = '', this.storageCell, this.newCells = const [], + this.user, }); final PackageCellsStateStatus status; final ProductArrivalPackageEx packageEx; final String message; final ApiStorageCell? storageCell; - final List newCells; + final List newCells; + final User? user; - List get storageCellNames => newCells.map((e) => e.storageCellName).toSet().toList() + List get storageCellNames => newCells.map((e) => e.newCell.storageCellName).toSet().toList() ..sort((a, b) => a.compareTo(b)); PackageCellsState copyWith({ @@ -32,14 +34,16 @@ class PackageCellsState { ProductArrivalPackageEx? packageEx, String? message, Optional? storageCell, - List? newCells + List? newCells, + User? user }) { return PackageCellsState( status: status ?? this.status, packageEx: packageEx ?? this.packageEx, message: message ?? this.message, storageCell: storageCell != null ? storageCell.orNull : this.storageCell, - newCells: newCells ?? this.newCells + newCells: newCells ?? this.newCells, + user: user ?? this.user ); } } diff --git a/lib/app/pages/product_arrivals/product_arrival/package_cells/package_view_cells_model.dart b/lib/app/pages/product_arrivals/product_arrival/package_cells/package_view_cells_model.dart index ee36ae8..be3df63 100644 --- a/lib/app/pages/product_arrivals/product_arrival/package_cells/package_view_cells_model.dart +++ b/lib/app/pages/product_arrivals/product_arrival/package_cells/package_view_cells_model.dart @@ -20,8 +20,9 @@ class PackageCellsViewModel extends PageViewModel deleteProductArrivalPackageNewCell(ProductArrivalPackageNewCell packageNewCell) async { - await app.dataStore.productArrivalsDao.deleteProductArrivalPackageNewCell(packageNewCell); + Future deleteProductArrivalPackageNewCell(ProductArrivalPackageNewCellEx packageNewCellEx) async { + await app.dataStore.productArrivalsDao.deleteProductArrivalPackageNewCell(packageNewCellEx.newCell); } - Future _placeProducts(ProductArrivalPackageEx packageEx, List newCells) async { + Future printProductLabel(Product product, int amount) async { + ProductLabel(product: product, user: state.user!).print( + amount: amount, + onError: (String error) => emit(state.copyWith(status: PackageCellsStateStatus.failure, message: error)) + ); + } + + Future _placeProducts( + ProductArrivalPackageEx packageEx, + List newCellsEx + ) async { try { ApiProductArrival newApiProductArrival = await Api(dataStore: app.dataStore).productArrivalsPlacePackageProducts( id: packageEx.package.id, - cells: newCells.map( - (e) => { 'storageCellId': e.storageCellId, 'productId': e.productId, 'amount': e.amount } - ).toList() + cells: newCellsEx.map((e) => { + 'storageCellId': e.newCell.storageCellId, + 'productId': e.newCell.productId, + 'amount': e.newCell.amount + }).toList() ); await app.dataStore.productArrivalsDao.clearProductArrivalPackageNewCells(); diff --git a/lib/app/pages/product_arrivals/product_arrival/product_arrival_page.dart b/lib/app/pages/product_arrivals/product_arrival/product_arrival_page.dart index 6cfeaea..a2d3335 100644 --- a/lib/app/pages/product_arrivals/product_arrival/product_arrival_page.dart +++ b/lib/app/pages/product_arrivals/product_arrival/product_arrival_page.dart @@ -9,11 +9,10 @@ import '/app/constants/strings.dart'; import '/app/constants/style.dart'; import '/app/data/database.dart'; import '/app/entities/entities.dart'; +import '/app/labels/product_arrival_packages_label.dart'; import '/app/pages/shared/page_view_model.dart'; import '/app/services/api.dart'; -import '/app/services/printer.dart'; import '/app/utils/format.dart'; -import '/app/utils/permissions.dart'; import '/app/widgets/widgets.dart'; import 'new_package/new_package_page.dart'; import 'new_unload_package/new_unload_package_page.dart'; @@ -302,7 +301,7 @@ class _ProductArrivalViewState extends State<_ProductArrivalView> { if (vm.state.unloadEnded && !vm.state.anyPackageAcceptStarted) { children.add(IconButton( icon: const Icon(Icons.print_sharp), - onPressed: vm.printPackageStickers, + onPressed: vm.printPackagesLabel, tooltip: 'Распечатать места', constraints: const BoxConstraints(), padding: const EdgeInsets.only(left: 8) diff --git a/lib/app/pages/product_arrivals/product_arrival/product_arrival_view_model.dart b/lib/app/pages/product_arrivals/product_arrival/product_arrival_view_model.dart index a30a1ec..a0f341c 100644 --- a/lib/app/pages/product_arrivals/product_arrival/product_arrival_view_model.dart +++ b/lib/app/pages/product_arrivals/product_arrival/product_arrival_view_model.dart @@ -1,8 +1,6 @@ part of 'product_arrival_page.dart'; class ProductArrivalViewModel extends PageViewModel { - Printer printer = Printer(); - ProductArrivalViewModel(BuildContext context, { required ProductArrivalEx productArrivalEx }) : super(context, ProductArrivalState(productArrivalEx: productArrivalEx)); @@ -55,33 +53,8 @@ class ProductArrivalViewModel extends PageViewModel printPackageStickers() async { - if (!await Permissions.hasBluetoothPermission()) { - emit(state.copyWith(message: 'Не разрешено соединение по Bluetooth', status: ProductArrivalStateStatus.failure)); - return; - } - - String labelCommand = state.productArrivalEx.packages.map((e) { - String formattedDate = Format.dateStr(state.productArrival.arrivalDate); - String command = ''' - SIZE 2.8,4.61 - GAP 0.18,0 - CODEPAGE UTF-8 - COUNTRY 061 - DIRECTION 0 - CLS - QRCODE 130,100,Q,10,A,0,M2,"${e.package.qr}" - TEXT 300,460,"5",0,1,1,2,"${e.package.number}" - TEXT 300,530,"3",0,1,1,2,"Приемка #${state.productArrival.number} от $formattedDate" - TEXT 300,560,"3",0,1,1,2,"Всего мест: ${state.productArrivalEx.packages.length}" - PRINT 1,1 - '''; - - return command; - }).toList().join('\n'); - - printer.printLabel( - labelCommand, + Future printPackagesLabel() async { + ProductArrivalPackagesLabel(productArrivalEx: state.productArrivalEx).print( onError: (String error) => emit(state.copyWith(status: ProductArrivalStateStatus.failure, message: error)) ); } diff --git a/lib/app/services/printer.dart b/lib/app/services/printer.dart index 480db52..1bacd14 100644 --- a/lib/app/services/printer.dart +++ b/lib/app/services/printer.dart @@ -5,7 +5,10 @@ import 'package:collection/collection.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart' as blue; import 'package:flutter_bluetooth_basic/flutter_bluetooth_basic.dart'; +import '/app/utils/permissions.dart'; + class Printer { + static const int kPaperWidth = 560; static final BluetoothManager _bluetoothManager = BluetoothManager.instance; static const String _printerNamePostfix = 'XP-P323B'; final Duration _scanTimeout = const Duration(seconds: 2); @@ -21,6 +24,12 @@ class Printer { return; } + if (!await Permissions.hasBluetoothPermission()) { + onError.call('Не разрешено соединение по Bluetooth'); + + return; + } + List data = utf8.encode(labelCommand).toList(); List devices = await _bluetoothManager.startScan(timeout: _scanTimeout); BluetoothDevice? device = devices.firstWhereOrNull((e) => e.name?.contains(_printerNamePostfix) ?? false); diff --git a/lib/app/utils/format.dart b/lib/app/utils/format.dart index 5781a87..4f292ca 100644 --- a/lib/app/utils/format.dart +++ b/lib/app/utils/format.dart @@ -18,4 +18,85 @@ class Format { static String timeStr(DateTime? dateTime) { return dateTime != null ? DateFormat.Hm('ru').format(dateTime) : ''; } + + /// Courtesy https://stackoverflow.com/a/71263526/5382447 + /// Wrap your string. + /// @param line - String line which need to be wrapped. + /// @param wrapLength - Wrapping threshold. Must be greater than 1. + /// @return + /// + static List wrapLine(String line, int wrapLength) { + List resultList = []; + + if (line.isEmpty) { + resultList.add(""); + return resultList; + } + + if (line.length <= wrapLength) { + resultList.add(line); + return resultList; + } + + List words = line.split(" "); + + for (String word in words) { + if (resultList.isEmpty) { + _addNewWord(resultList, word, wrapLength); + } else { + String lastLine = resultList.last; + + if (lastLine.length + word.length < wrapLength) { + lastLine = lastLine + word + " "; + resultList.last = lastLine; + } else if (lastLine.length + word.length == wrapLength) { + lastLine = lastLine + word; + resultList.last = lastLine; + } else { + if (_isThereMuchSpace(lastLine, wrapLength.toDouble())) { + _breakLongWord(resultList, word, wrapLength, lastLine.length); + } else { + _addNewWord(resultList, word, wrapLength); + } + } + } + } + + return resultList; + } + + static void _addNewWord(List resultList, String word, int wrapLength) { + if (word.length < wrapLength) { + resultList.add(word + " "); + } else if (word.length == wrapLength) { + resultList.add(word); + } else { + _breakLongWord(resultList, word, wrapLength, 0); + } + } + + static void _breakLongWord(List resultList, String word, int wrapLength, int offset) { + String part = word.substring(0, (wrapLength - offset) - 1); + + if (offset > 1) { + String lastLine = resultList.last; + lastLine = lastLine + part + "-"; + resultList.last = lastLine; + } else { + resultList.add(part + "-"); + } + + String nextPart = word.substring((wrapLength - offset) - 1, word.length); + + if (nextPart.length > wrapLength) return _breakLongWord(resultList, nextPart, wrapLength, 0); + if (nextPart.length == wrapLength) return resultList.add(nextPart); + + return resultList.add(nextPart + " "); + } + + static bool _isThereMuchSpace(String line, double lineLength) { + double expectedPercent = (lineLength * 65) / 100; + if (line.length <= expectedPercent) return true; + return false; + } }