diff --git a/lib/core/entity/transaction_rec_entity.dart b/lib/core/entity/transaction_rec_entity.dart new file mode 100644 index 0000000..f63f931 --- /dev/null +++ b/lib/core/entity/transaction_rec_entity.dart @@ -0,0 +1,38 @@ +const String transactionRecTableName = 'transactions_rec'; +const String transactionRecColumnId = 'id'; +const String transactionRecTransactionIdRef = 'transaction_id'; +const String transactionRecColumnData = 'data'; +const String transactionRecColumnCreatedAt = 'createdAt'; + + +class TransactionRec { + + TransactionRec(); + + TransactionRec.fromMap(Map map) { + id = map[transactionRecColumnId] as int; + transactionId = map[transactionRecTransactionIdRef] as int; + data = map[transactionRecColumnData] as String; + createdAt = map[transactionRecColumnCreatedAt] as String; + } + + int? id; + int? transactionId; + String? data; + String? createdAt; + + Map toMap() { + final Map map = { + transactionRecTransactionIdRef: transactionId, + transactionRecColumnData: data, + transactionRecColumnCreatedAt: createdAt, + }; + if (id != null) { + map[transactionRecColumnId] = id; + } + return map; + } + + +} + diff --git a/lib/core/models/entity_data/transaction_data.dart b/lib/core/models/entity_data/transaction_data.dart new file mode 100644 index 0000000..bebfbca --- /dev/null +++ b/lib/core/models/entity_data/transaction_data.dart @@ -0,0 +1,23 @@ +import 'package:satu/core/utils/utils_parse.dart'; + +class TransactionData { + TransactionData(); + + TransactionData.fromMap(dynamic map) { + contragentName = map['contragentName'] as String; + card = map['card'] as double; + nal = map['nal'] as double; + } + String contragentName = ''; + double card = 0; + double nal = 0; + + Map toMap() { + final Map map = { + 'contragentName': contragentName, + 'card' : card, + 'nal' : nal, + }; + return map; + } +} diff --git a/lib/core/redux/actions/sell_actions.dart b/lib/core/redux/actions/sell_actions.dart index c3fdf8f..3594fef 100644 --- a/lib/core/redux/actions/sell_actions.dart +++ b/lib/core/redux/actions/sell_actions.dart @@ -7,6 +7,8 @@ import 'package:redux_thunk/redux_thunk.dart'; import 'package:satu/core/entity/category_entity.dart'; import 'package:satu/core/entity/goods_entity.dart'; import 'package:satu/core/entity/transaction_entity.dart'; +import 'package:satu/core/entity/transaction_rec_entity.dart'; +import 'package:satu/core/models/entity_data/transaction_data.dart'; import 'package:satu/core/models/flow/product_dao.dart'; import 'package:satu/core/models/flow/transaction_state.dart'; import 'package:satu/core/redux/state/sell_state.dart'; @@ -19,9 +21,8 @@ import '../store.dart'; @immutable class SetSellStateAction { + const SetSellStateAction(this.sellState); final SellState sellState; - - SetSellStateAction(this.sellState); } final Logger log = getLogger('SetSellStateAction'); @@ -31,33 +32,16 @@ final DbService _dbService = locator(); ThunkAction counterOrEditSellItem( {required int transactionId, required double counter, double? price}) { return (Store store) async { - log.i('counterSellItem'); - int? appCompanyId = store.state.userState!.auth!.companyId; - String? uuid = store.state.sellState!.transactionState!.uuid; + log.i( + 'counterSellItem id = $transactionId counter = $counter, price = $price', + ); + final Map? map = + await _dbService.queryById(transactionRecTableName, transactionId); - Transaction? transaction; - - if (uuid != null) { - final List> set = - await _dbService.queryRowsWithWhere( - transactionTableName, - '$transactionColumnAppCompanyId = ? ' - ' and $transactionColumnStatus = ? ' - ' and $transactionColumnType = ? ' - ' and $transactionColumnId = ?', - [ - appCompanyId, - transactionStatusPrepare, - transactionTypeSell, - transactionId - ], - orderBy: '$transactionColumnCreatedAt desc'); - if (set.isNotEmpty) { - transaction = Transaction.fromMap(set.first); - } - } - if (transaction != null) { - final ProductDao item = ProductDao.fromMap(jsonDecode(transaction.data!)); + if (map != null) { + final TransactionRec transactionRec = TransactionRec.fromMap(map); + final ProductDao item = + ProductDao.fromMap(jsonDecode(transactionRec.data!)); if (price != null) { item.price = price; item.count = counter; @@ -65,8 +49,8 @@ ThunkAction counterOrEditSellItem( final String val = ((item.count ?? 0) + counter).toStringAsFixed(5); item.count = num.parse(val); } - transaction.data = jsonEncode(item.toMap()); - _dbService.update(transactionTableName, transaction.toMap()); + transactionRec.data = jsonEncode(item.toMap()); + _dbService.update(transactionRecTableName, transactionRec.toMap()); } // refresh from db ? after save data await loadSellData(store); @@ -77,39 +61,63 @@ ThunkAction addSellItem({required Good good, String? excise}) { return (Store store) async { log.i('addSellItem'); final int? appCompanyId = store.state.userState!.auth!.companyId; - String? uuid = store.state.sellState!.transactionState!.uuid; Transaction? transaction; - if (uuid != null) { - List> set = await _dbService.queryRowsWithWhere( - transactionTableName, - '$transactionColumnAppCompanyId = ? ' - ' and $transactionColumnStatus = ? ' - ' and $transactionColumnType = ?', - [appCompanyId, transactionStatusPrepare, transactionTypeSell], - orderBy: '$transactionColumnCreatedAt desc'); - if (set.isNotEmpty) { - for (Map map in set) { - Transaction _transaction = Transaction.fromMap(map); - ProductDao _product = - ProductDao.fromMap(jsonDecode(_transaction.data!)); - if (_product.id == good.id && _product.excise == excise) { - transaction = _transaction; - break; - } + final List> transactions = + await _dbService.queryRowsWithWhere( + transactionTableName, + '$transactionColumnAppCompanyId = ? ' + ' and $transactionColumnStatus = ? ' + ' and $transactionColumnType = ?', + [appCompanyId, transactionStatusPrepare, transactionTypeSell], + orderBy: '$transactionColumnCreatedAt desc'); + if (transactions.isNotEmpty) { + for (final Map map in transactions) { + transaction = Transaction.fromMap(map); + } + } + + if (transaction == null) { + const uuidTool = Uuid(); + final String uuid = uuidTool.v4(); + final TransactionData transactionData = TransactionData(); + transaction = Transaction() + ..uuid = uuid + ..status = transactionStatusPrepare + ..appCompanyId = appCompanyId + ..type = transactionTypeSell + ..createdAt = DateTime.now().toIso8601String() + ..data = jsonEncode(transactionData.toMap()); + final int returnKey = + await _dbService.insert(transactionTableName, transaction.toMap()); + transaction.id = returnKey; + } + + final List> recs = await _dbService.queryRowsWithWhere( + transactionRecTableName, + '$transactionRecTransactionIdRef = ? ', + [transaction.id]); + ProductDao? item; + if (recs.isNotEmpty) { + for (final Map map in recs) { + final TransactionRec transactionRec = TransactionRec.fromMap(map); + final ProductDao _item = + ProductDao.fromMap(jsonDecode(transactionRec.data!)); + if (_item.id == good.id) { + log.i(map); + _item.count = _item.count! + 1; + transactionRec.data = jsonEncode(_item.toMap()); + await _dbService.update( + transactionRecTableName, transactionRec.toMap()); + item = _item; + break; } } } - if (transaction != null) { - ProductDao item = ProductDao.fromMap(jsonDecode(transaction.data!)); - item..count = item.count! + 1; - transaction.data = jsonEncode(item.toMap()); - transaction.createdAt = DateTime.now().toIso8601String(); - _dbService.update(transactionTableName, transaction.toMap()); - } else { - ProductDao item = new ProductDao() + if (item == null) { + item = ProductDao() ..id = good.id ..price = good.price ..article = good.articul @@ -119,30 +127,22 @@ ThunkAction addSellItem({required Good good, String? excise}) { ..excise = excise; //category add logic if (good.categoryId != null) { - List> set = await _dbService + final List> set = await _dbService .queryRowsWithWhere(categoryTableName, 'id = ?', [good.categoryId]); if (set.isNotEmpty) { - Category category = Category.fromMap(set.first); + final Category category = Category.fromMap(set.first); item.categoryId = category.id; item.categoryName = category.name; } } - - if (uuid == null) { - var uuidTool = Uuid(); - ; - uuid = uuidTool.v4(); - } - - transaction = new Transaction() - ..uuid = uuid - ..status = transactionStatusPrepare - ..appCompanyId = appCompanyId - ..type = transactionTypeSell - ..createdAt = DateTime.now().toIso8601String() - ..data = jsonEncode(item.toMap()); - await _dbService.insert(transactionTableName, transaction.toMap()); + final TransactionRec rec = TransactionRec() + ..data = jsonEncode(item.toMap()) + ..transactionId = transaction.id + ..createdAt = DateTime.now().toIso8601String(); + log.i(rec.toMap()); + await _dbService.insert(transactionRecTableName, rec.toMap()); } + // refresh from db ? after save data await loadSellData(store); }; @@ -150,11 +150,21 @@ ThunkAction addSellItem({required Good good, String? excise}) { ThunkAction removeSellItem({required int transactionId}) { return (Store store) async { - int? appCompanyId = store.state.userState!.auth!.companyId; - String? uuid = store.state.sellState!.transactionState!.uuid; + final List> set = await _dbService + .queryRowsWithWhere(transactionRecTableName, 'id = ?', [transactionId]); + final TransactionRec rec = TransactionRec.fromMap(set.first); - int count = await _dbService.delete(transactionTableName, transactionId); - log.i('removeSellItem ${count} by transactionId:${transactionId}'); + final int countdeleted = + await _dbService.delete(transactionRecTableName, transactionId); + + final int? count = await _dbService.queryRowCount(transactionRecTableName, + where: '$transactionRecTransactionIdRef = ${rec.transactionId}'); + if ((count ?? 0) < 1 && rec.transactionId != null) { + await _dbService.delete(transactionTableName, rec.transactionId!); + } + + log.i('removeSellItem $countdeleted ' + 'last $count by transactionId:$transactionId'); // refresh from db ? after save data await loadSellData(store); @@ -164,15 +174,13 @@ ThunkAction removeSellItem({required int transactionId}) { Future removeAllSellData(Store store) async { try { log.i('removeAllSellData'); - int? appCompanyId = store.state.userState!.auth!.companyId; - String? uuid = store.state.sellState!.transactionState!.uuid; + final int? appCompanyId = store.state.userState!.auth!.companyId; await _dbService.deleteByWhere( transactionTableName, '$transactionColumnAppCompanyId = ? ' ' and $transactionColumnStatus = ? ' - ' and ${transactionColumnType} = ?' - ' and ${transactionColumnUuid} = ?', - [appCompanyId, transactionStatusPrepare, transactionTypeSell, uuid]); + ' and $transactionColumnType = ?', + [appCompanyId, transactionStatusPrepare, transactionTypeSell]); await loadSellData(store); } catch (e, stack) { log.e('removeAllSellData', e, stack); @@ -182,20 +190,29 @@ Future removeAllSellData(Store store) async { Future loadSellData(Store store) async { try { log.i('loadSellData'); - int? appCompanyId = store.state.userState!.auth!.companyId; - List> set = await _dbService.queryRowsWithWhere( + final int? appCompanyId = store.state.userState!.auth!.companyId; + final List> set = await _dbService.queryRowsWithWhere( transactionTableName, - '$transactionColumnAppCompanyId = ? and $transactionColumnStatus = ? and ${transactionColumnType} = ?', + '$transactionColumnAppCompanyId = ?' + ' and $transactionColumnStatus = ?' + ' and $transactionColumnType = ?', [appCompanyId, transactionStatusPrepare, transactionTypeSell], orderBy: '$transactionColumnCreatedAt desc'); - List list = []; + final List list = []; String? uuid; - for (Map map in set) { - Transaction transaction = Transaction.fromMap(map); + if (set.isNotEmpty) { + final Transaction transaction = Transaction.fromMap(set.first); uuid = transaction.uuid; - ProductDao productDao = ProductDao.fromMap(jsonDecode(transaction.data!)); - productDao.transactionId = transaction.id; - list.add(productDao); + final List> recs = + await _dbService.queryRowsWithWhere(transactionRecTableName, + '$transactionRecTransactionIdRef = ? ', [transaction.id], + orderBy: '$transactionRecColumnCreatedAt desc'); + for (final Map map in recs) { + final TransactionRec rec = TransactionRec.fromMap(map); + final ProductDao productDao = ProductDao.fromMap(jsonDecode(rec.data!)); + productDao.transactionId = rec.id; + list.add(productDao); + } } store.dispatch(SetSellStateAction(SellState( items: list, transactionState: TransactionState()..uuid = uuid))); diff --git a/lib/core/services/db_service.dart b/lib/core/services/db_service.dart index ac7d4f0..907a5ea 100644 --- a/lib/core/services/db_service.dart +++ b/lib/core/services/db_service.dart @@ -4,13 +4,14 @@ import 'package:satu/core/base/base_service.dart'; import 'package:satu/core/entity/category_entity.dart'; import 'package:satu/core/entity/goods_entity.dart'; import 'package:satu/core/entity/transaction_entity.dart'; +import 'package:satu/core/entity/transaction_rec_entity.dart'; import 'package:sqflite/sqflite.dart'; import 'package:path/path.dart'; import 'package:path_provider/path_provider.dart'; class DbService extends BaseService { - static const _databaseName = "AmanSatuDb.db"; - static const _databaseVersion = 1; + static const _databaseName = 'AmanSatuDb.db'; + static const _databaseVersion = 2; // make this a singleton class DbService._privateConstructor(); @@ -39,7 +40,8 @@ class DbService extends BaseService { //Goods table await db.execute('DROP TABLE IF EXISTS $goodTableName;'); await db.execute('DROP TABLE IF EXISTS $categoryTableName;'); - //await db.execute('DROP TABLE IF EXISTS $Voucher_tableName;'); + await db.execute('DROP TABLE IF EXISTS $transactionTableName;'); + await db.execute('DROP TABLE IF EXISTS $transactionRecTableName;'); log.i('dropped tables'); _onCreate(db, newVersion); } @@ -47,6 +49,7 @@ class DbService extends BaseService { Future _onCreate(Database db, int version) async { log.i('create tables'); //Goods table + await db.execute(''' CREATE TABLE IF NOT EXISTS $goodTableName ( $GoodColumnId integer primary key unique, @@ -82,6 +85,17 @@ class DbService extends BaseService { $transactionColumnCreatedAt text not null ); '''); + await db.execute(''' + CREATE TABLE IF NOT EXISTS $transactionRecTableName ( + $transactionRecColumnId integer primary key autoincrement, + $transactionRecTransactionIdRef integer not null, + $transactionRecColumnData text, + $transactionRecColumnCreatedAt text not null, + CONSTRAINT fk_$transactionTableName + FOREIGN KEY ($transactionRecTransactionIdRef) + REFERENCES $transactionTableName($transactionColumnId) + ); + '''); } // Inserts a row in the database where each key in the Map is a column name @@ -125,12 +139,21 @@ class DbService extends BaseService { return result; } + Future?> queryById(String table, int id, + {String? idColumnName}) async { + final Database db = await instance.database; + final List> result = await db + .query(table, where: '${idColumnName ?? 'id'} = ?', whereArgs: [id]); + + return result.isNotEmpty ? result.first : null; + } + // All of the methods (insert, query, update, delete) can also be done using // raw SQL commands. This method uses a raw query to give the row count. - Future queryRowCount(String table) async { + Future queryRowCount(String table, {String? where}) async { final Database db = await instance.database; - final int? result = - Sqflite.firstIntValue(await db.rawQuery('SELECT COUNT(*) FROM $table')); + final int? result = Sqflite.firstIntValue(await db.rawQuery( + 'SELECT COUNT(*) FROM $table ${where != null ? 'where $where' : ''}')); return result; }