From c71e07e6cfdf4a71299d59828dbf332cf8fb8b82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arttu=20Ylh=C3=A4vuori?= <10089872+areee@users.noreply.github.com> Date: Fri, 24 Jun 2022 13:21:46 +0300 Subject: [PATCH] Enhancement 15 (#18) * Update Dart SDK version (2.17.1 -> 2.17.3) & kassakuitti version * Fix an error with parsing an S-kaupat HTML file * Update dependencies (incl. dev dependencies) * Update transitive dependencies * Changes to arg commands - Move handleArgCommands method into own file - Update help command - Add initially hive command * Some refactoring * Pull Hive initialization to the root level & add count command for Hive CLI * Add methods for Hive CLI & add isNullOrEmpty String extension * Update add, readAll & searchBy methods in Hive CLI * Make needed Hive methods awaitable / asynchronous * Make ean_handler awaitable / asynchronous & close the box in the main method * Update Hive read methods to show the key value (currently an order number) * Fix delete method to delete based on given order number * Fix update method of hive_handling * Refactor printing methods * Fix div parsing in load_html_s_kaupat * Removed '_countProducts' from '_updateProduct' method * Some refactoring into update & delete methods * Fix a bug with digit-beginning receipt product * Refactor update & delete methods * Add installation page & update readme * Add developing page & update readme * Update readme * Update readme --- DEVELOPING.md | 9 + INSTALLATION.md | 23 ++ README.md | 60 +++-- bin/constants.dart | 1 + bin/dart_kassakuitti_cli.dart | 78 +++---- bin/hive_handling.dart | 221 ++++++++++++++++++ bin/models/hive_product.dart | 2 +- bin/run_main_program.dart | 56 +++++ bin/specific/s_kaupat/ean_handler.dart | 28 +-- .../s_kaupat/strings_to_receipt_products.dart | 2 +- bin/utils/arg_selector_helper.dart | 3 +- bin/utils/extensions/string_extension.dart | 12 + bin/utils/parse_kassakuitti_arguments.dart | 5 +- bin/utils/printing_helper.dart | 18 +- pubspec.lock | 57 ++--- pubspec.yaml | 16 +- 16 files changed, 443 insertions(+), 148 deletions(-) create mode 100644 DEVELOPING.md create mode 100644 INSTALLATION.md create mode 100644 bin/constants.dart create mode 100644 bin/hive_handling.dart create mode 100644 bin/run_main_program.dart create mode 100644 bin/utils/extensions/string_extension.dart diff --git a/DEVELOPING.md b/DEVELOPING.md new file mode 100644 index 0000000..7c0a982 --- /dev/null +++ b/DEVELOPING.md @@ -0,0 +1,9 @@ +## Generate `hive_product.g.dart` file + +You can generate `hive_product.g.dart` file by running: + +``` +dart run build_runner build +``` + +This generating process is needed before running the program for the first time. \ No newline at end of file diff --git a/INSTALLATION.md b/INSTALLATION.md new file mode 100644 index 0000000..5ba468b --- /dev/null +++ b/INSTALLATION.md @@ -0,0 +1,23 @@ +# Installation + +## Install Chrome extension & clone this project + +1. Download a Chrome extension called "[snapshot-as-html](https://github.com/areee/snapshot-as-html)" (edited by the author of this project). + - In the [latest release page](https://github.com/areee/snapshot-as-html/releases/latest), go to the assets section and click the "Source code (zip)" link. It'll download the source code to your computer. + - Unzip the zip file. + - Open Google Chrome and go to the [Extensions page](chrome://extensions) (chrome://extensions). + - Enable the developer mode and click "Load unpacked". Browse to the unzipped folder (e.g. `snapshot-as-html-0.1.0`) and go to the subdirectory (`snapshot-as-html`). That folder should include all the extension files, e.g. `manifest.json`. Click "Select" in the open dialog and Google Chrome will load the extension. +2. Git clone this project (or Code → Download ZIP) under your Documents folder (or anywhere you like). Set an alias to use it with `kassakuitti` command (see the next section). + +## Set an alias + +Use `kassakuitti` alias by adding the row below to your profile file. Here we're assuming you have cloned this project under your Documents folder. + +``` +alias kassakuitti='dart run $HOME/Documents/dart_kassakuitti_cli/bin/dart_kassakuitti_cli.dart' +``` + +If you're unsure where to save the alias, this might help you: + +- If you're using _Zsh_ as your shell, use `~/.zshrc` profile file. +- If you're using _Bash_ as your shell, use `~/.bash_profile` profile file. \ No newline at end of file diff --git a/README.md b/README.md index 6ad101a..6ddfdd8 100644 --- a/README.md +++ b/README.md @@ -7,18 +7,13 @@ ## Installation -1. Download a Chrome extension called "[snapshot-as-html](https://github.com/areee/snapshot-as-html)" (edited by the author of this project) - - In the [latest release page](https://github.com/areee/snapshot-as-html/releases/latest), go to the assets section and click the "Source code (zip)" link. It'll download the source code to your computer. - - Unzip the zip file. - - Open Google Chrome and go to the [Extensions page](chrome://extensions) (chrome://extensions). - - Enable the developer mode and click "Load unpacked". Browse to the unzipped folder (e.g. `snapshot-as-html-0.1.0`) and go to the subdirectory (`snapshot-as-html`). That folder should include all the extension files, e.g. `manifest.json`. Click "Select" in the open dialog and Google Chrome will load the extension. -2. Git clone this project (or Code → Download ZIP). Add an [alias](#alias) to use it with `kassakuitti` command. +See the installation in [its own page](https://github.com/areee/dart_kassakuitti_cli/blob/main/INSTALLATION.md). ## Usage ### Needed files - An EAN file = an HTML file (.html) → needed when using both S-kaupat and K-ruoka - - Generate an HTML file by using `snapshot-as-html` project (see the [installation](#installation)). + - Generate an HTML file by using `snapshot-as-html` project (see the [installation](https://github.com/areee/dart_kassakuitti_cli/blob/main/INSTALLATION.md)). - To generate that, go to an active order page of an online store: - [s-kaupat.fi](https://www.s-kaupat.fi) (profile image → "Tilaukset" → "Katso tilaustiedot") or - [k-ruoka.fi](https://www.k-ruoka.fi) (profile image → "Tilaukset" → expand the latest order). @@ -30,15 +25,9 @@ - Select a cash receipt you want to view. Select needed rows by painting from the first product row to the total row. Copy them. - Open a text editor (e.g. Notepad or TextEdit) and paste copied cash receipt rows. Save the file as a plain text file (.txt). -### Default usage +### Basic usage -The basic usage looks like this (an assumption is that we're in the project folder): - -``` -dart run bin/dart_kassakuitti_cli.dart run -t [a path to the cash receipt file] -h [a path to the EAN file] -s [S-kaupat or K-ruoka] -c [a path to generated CSV files] -``` - -Or, by using the [alias](#alias) (works anywhere in your local environment): +The basic usage looks like this: ``` kassakuitti run -t [a path to the cash receipt file] -h [a path to the EAN file] -s [S-kaupat or K-ruoka] -c [a path to generated CSV files] @@ -47,7 +36,7 @@ kassakuitti run -t [a path to the cash receipt file] -h [a path to the EAN file] You can define - a cash receipt (`-t` = text file), - an EAN products file (`-h` = html file), -- (optional: which food online store to use (`-s` = store)) and +- optionally: which food online store to use (`-s` = store) and - where to save the output files (`-c` = CSV file). S-kaupat is a default choice for the food online store selection (`-s`). @@ -55,19 +44,13 @@ S-kaupat is a default choice for the food online store selection (`-s`). #### An example ``` -kassakuitti run -t /Users/username/Downloads/cash_receipt.txt -h /Users/username/Downloads/https___www.s-kaupat.fi_tilaus_product_id-generating_time.html -s S-kaupat -c /Users/username/Downloads +kassakuitti run -t /Users/username/Downloads/cash_receipt.txt -h /Users/username/Downloads/https___www.s-kaupat.fi_tilaus_product_id-generating_time.html -s S-kaupat -c ~/Downloads ``` ### Help If you want to get all the available commands, you can just type: -``` -dart run bin/dart_kassakuitti_cli.dart help -``` - -Or, by using the [alias](#alias): - ``` kassakuitti help ``` @@ -77,27 +60,36 @@ kassakuitti help If you want some basic information about this program (e.g. the description, the version number or the project homepage), just type: ``` -dart run bin/dart_kassakuitti_cli.dart +kassakuitti ``` -Or, by using the [alias](#alias): +The CLI gives also the same result when typing anything that's not recognized by the program, e.g.: ``` -kassakuitti +kassakuitti moro ``` -## Alias +(For non-Finnish speakers: "moro" means hello in Tampere, Finland.) + +### Hive handling -If you want to get an easier command, you can create an alias into Zsh or Bash profile file (e.g. `~/.zshrc` when using Zsh and `~/.bashrc` when using Bash). This line adds an alias `kassakuitti` into the profile file (let's assume that this `dart_kassakuitti_cli` project locates under your Documents folder): +You can handle a local Hive database that the program is using by typing: ``` -alias kassakuitti='dart run $HOME/Documents/dart_kassakuitti_cli/bin/dart_kassakuitti_cli.dart' +kassakuitti hive ``` -## Generate `hive_product.g.dart` file +This starts an own interface for handling the following alternatives: -You can generate `hive_product.g.dart` file by running: +1. Create a receipt name – EAN name product. +2. Read all products (gives index numbers for each product). +3. Search a product by a keyword (gives index numbers for each product). +4. Update a product by an index number. +5. Delete a product by an index number. +6. Count products. -``` -dart run build_runner build -``` \ No newline at end of file +Each product in the Hive database has an own index number. If a product gets deleted, the next new product won't get the same index number that the previously deleted product had but a next unused index number. + +## Participate to developing + +See a brief instruction for developing is in [its own page](https://github.com/areee/dart_kassakuitti_cli/blob/main/DEVELOPING.md). \ No newline at end of file diff --git a/bin/constants.dart b/bin/constants.dart new file mode 100644 index 0000000..2e00ced --- /dev/null +++ b/bin/constants.dart @@ -0,0 +1 @@ +const kHiveBoxName = 'hiveProducts'; diff --git a/bin/dart_kassakuitti_cli.dart b/bin/dart_kassakuitti_cli.dart index 8cc6472..c62622e 100644 --- a/bin/dart_kassakuitti_cli.dart +++ b/bin/dart_kassakuitti_cli.dart @@ -1,72 +1,54 @@ import 'dart:io'; import 'package:args/args.dart'; -import 'read_ean_products.dart'; -import 'ean_products_2_csv.dart'; -import 'specific/s_kaupat/ean_handler.dart'; -import 'specific/s_kaupat/read_receipt_products.dart'; -import 'specific/s_kaupat/receipt_products_2_csv.dart'; +import 'package:hive/hive.dart'; + +import 'constants.dart'; +import 'hive_handling.dart'; +import 'models/hive_product.dart'; +import 'run_main_program.dart'; import 'utils/arg_selector_helper.dart'; import 'utils/parse_kassakuitti_arguments.dart'; import 'utils/printing_helper.dart'; -import 'utils/shop_selector_helper.dart'; void main(List arguments) async { exitCode = 0; // presume success + var hiveProducts = await _initializeHiveProducts(); var parser = getParser(); var argResults = parser.parse(arguments); - await handleArgCommands(argResults, parser); + await _handleArgCommands(argResults, parser, hiveProducts); + + hiveProducts.close(); } /// Handles the commands in the arguments. -Future handleArgCommands(ArgResults argResults, ArgParser parser) async { +Future> _handleArgCommands(ArgResults argResults, + ArgParser parser, Box hiveProducts) async { + // Run command + if (argResults.command?.name == ArgSelector.run.value) { + await runMainProgram(argResults, hiveProducts); + } // Help command - if (argResults.command?.name == ArgSelector.help.value) { - print('Help:\n${parser.usage}'); + else if (argResults.command?.name == ArgSelector.help.value) { + printHelpers(parser); } - // Run command - else if (argResults.command?.name == ArgSelector.run.value) { - print('\nRunning...\n'); - - var selectedTextFile = argResults[ArgSelector.textFile.value] as String?; - var selectedHtmlFile = argResults[ArgSelector.htmlFile.value] as String; - var selectedStore = argResults[ArgSelector.foodOnlineStore.value] as String; - var csvFilesPath = argResults[ArgSelector.csvPath.value] as String; - - printSelectedValues( - selectedTextFile, selectedHtmlFile, selectedStore, csvFilesPath); - - try { - if (ShopSelector.sKaupat.value == selectedStore) { - var receiptProducts = - await readReceiptProducts(selectedTextFile!, csvFilesPath); - var eanProducts = await readEANProducts( - selectedHtmlFile, ShopSelector.sKaupat, csvFilesPath); - - await eanHandler(receiptProducts, eanProducts.toList()); - - receiptProducts2CSV(receiptProducts, csvFilesPath); - eanProducts2CSV(eanProducts, csvFilesPath, ShopSelector.sKaupat.name); - } else if (ShopSelector.kRuoka.value == selectedStore) { - var eanProducts = await readEANProducts( - selectedHtmlFile, ShopSelector.kRuoka, csvFilesPath); - - eanProducts2CSV(eanProducts, csvFilesPath, ShopSelector.kRuoka.name); - } else { - print('Unknown store: $selectedStore'); - exitCode = 1; - } - } on Exception catch (e) { - print('Error: $e'); - exitCode = 1; - } - - print('\nDone!'); + // Hive (storage) command + else if (argResults.command?.name == ArgSelector.hive.value) { + await hiveHandling(hiveProducts); } // Empty command (or other commands, e.g. 'moro' / 'hello') else { await printBasicInfo(parser); } + + return hiveProducts; +} + +/// Initializes the Hive products. +Future> _initializeHiveProducts() async { + Hive.init(Directory.current.path); + Hive.registerAdapter(HiveProductAdapter()); + return await Hive.openBox(kHiveBoxName); } diff --git a/bin/hive_handling.dart b/bin/hive_handling.dart new file mode 100644 index 0000000..4d9a3c2 --- /dev/null +++ b/bin/hive_handling.dart @@ -0,0 +1,221 @@ +import 'dart:io'; + +import 'package:hive/hive.dart'; + +import 'models/hive_product.dart'; +import 'utils/extensions/string_extension.dart'; + +/// Hive handling (CRUD for storage handling). +Future> hiveHandling(Box hiveProducts) async { + while (true) { + print(''' + + *** Hive handling *** + 1. Create + 2. Read all + 3. Search by keyword + 4. Update + 5. Delete + 6. Count + Empty command or something else to exit. + '''); + + var input = stdin.readLineSync(); + + switch (input) { + case '1': + await _addProduct(hiveProducts); + break; + case '2': + _readAllProducts(hiveProducts); + break; + case '3': + _searchByKeyword(hiveProducts); + break; + case '4': + await _updateProduct(hiveProducts); + break; + case '5': + await _deleteProduct(hiveProducts); + break; + case '6': + _countProducts(hiveProducts); + break; + default: + print('Exiting...'); + return hiveProducts; + } + } +} + +/// Adds a product to the storage. +Future _addProduct(Box hiveProducts) async { + print('Enter the receipt name of the product:'); + var name = stdin.readLineSync(); + + print('Enter the EAN name of the product:'); + var eanName = stdin.readLineSync(); + + if (name.isNotNullOrEmpty() && eanName.isNotNullOrEmpty()) { + print('You entered: $name, $eanName'); + print('Do you want to add this product? (y/n)'); + var input = stdin.readLineSync(); + + if (input == 'y') { + await hiveProducts + .add(HiveProduct(receiptName: name!, eanName: eanName!)); + print('Product added!'); + _countProducts(hiveProducts); + } else { + print('Product not added!'); + } + } +} + +/// Reads all products from the storage. +void _readAllProducts(Box hiveProducts) { + _countProducts(hiveProducts); + print('All products:'); + _printProducts(products: hiveProducts); +} + +/// Prints Hive products. +void _printProducts( + {required Box products, Iterable? filteredProducts}) { + if (filteredProducts == null) { + for (var product in products.keys) { + _printSingleProduct(products: products, product: product); + } + } else { + for (var product in filteredProducts) { + _printSingleProduct(products: products, product: product); + } + } +} + +/// Prints single Hive product. +void _printSingleProduct( + {required Box products, required dynamic product}) { + print('\t#$product: ${products.get(product)}'); +} + +/// Search by keyword in the storage. +void _searchByKeyword(Box hiveProducts) { + print('Enter a keyword:'); + var keyword = stdin.readLineSync(); + + if (keyword.isNotNullOrEmpty()) { + print('You entered: $keyword'); + + var filteredProducts = hiveProducts.keys.where((key) => hiveProducts + .get(key)! + .receiptName + .toLowerCase() + .contains(keyword!.toLowerCase())); + + var amount = filteredProducts.length; + + print('Found $amount ${amount == 1 ? 'product' : 'products'}:'); + + _printProducts(products: hiveProducts, filteredProducts: filteredProducts); + } +} + +/// Updates a product in the storage. +Future _updateProduct(Box hiveProducts) async { + var orderNumber = _getOrderNumberAndPrintProduct(hiveProducts); + if (orderNumber == -1) return; + + print('Enter the new receipt name of the product:'); + var name = stdin.readLineSync(); + + print('Enter the new EAN name of the product:'); + var eanName = stdin.readLineSync(); + + if (name.isNotNullOrEmpty() && eanName.isNotNullOrEmpty()) { + print('You entered: $name, $eanName'); + print('Do you want to update this product? (y/n)'); + var input = stdin.readLineSync(); + + if (input == 'y') { + await hiveProducts.put( + orderNumber, HiveProduct(receiptName: name!, eanName: eanName!)); + print('Product updated!'); + } else { + print('Product not updated!'); + } + } +} + +/// Delete a product from the storage. +Future _deleteProduct(Box hiveProducts) async { + var orderNumber = _getOrderNumberAndPrintProduct(hiveProducts); + if (orderNumber == -1) return; + + print('Do you want to delete this product? (y/n)'); + var input = stdin.readLineSync(); + + if (input == 'y') { + await hiveProducts.delete(orderNumber); + print('Product deleted!'); + _countProducts(hiveProducts); + } else { + print('Product not deleted!'); + } +} + +/// Asks the user to give an order number. +int? _askUserToGiveOrderNumber() { + print('Enter the order number of the product:'); + var orderNumber = stdin.readLineSync(); + + if (orderNumber.isNotNullOrEmpty()) { + return int.tryParse(orderNumber!); + } + return null; +} + +/// Checks if an order number is valid. +bool _isValidOrderNumber(int? orderNumber) { + return orderNumber != null && orderNumber >= 0; +} + +/// Handles an order number. +int _handleOrderNumber() { + var orderNumber = _askUserToGiveOrderNumber(); + + if (!_isValidOrderNumber(orderNumber)) { + print('Invalid order number!'); + return -1; + } + return orderNumber!; +} + +/// Gets a product. +HiveProduct? _getProduct(Box hiveProducts, int orderNumber) { + var product = hiveProducts.get(orderNumber); + + if (product == null) { + print('Product not found!'); + return null; + } + + print('Product: $product'); + return product; +} + +/// Gets an order number (and gives a product information). +int _getOrderNumberAndPrintProduct(Box hiveProducts) { + var orderNumber = _handleOrderNumber(); + if (orderNumber == -1) return -1; + + var product = _getProduct(hiveProducts, orderNumber); + if (product == null) return -1; + + return orderNumber; +} + +/// Counts the products in the storage. +void _countProducts(Box hiveProducts) { + print('Amount of products: ${hiveProducts.length}'); +} diff --git a/bin/models/hive_product.dart b/bin/models/hive_product.dart index d7a9265..d985638 100644 --- a/bin/models/hive_product.dart +++ b/bin/models/hive_product.dart @@ -14,6 +14,6 @@ class HiveProduct extends HiveObject { @override String toString() { - return 'ReceiptName: $receiptName, eanName: $eanName'; + return 'receiptName: $receiptName, eanName: $eanName'; } } diff --git a/bin/run_main_program.dart b/bin/run_main_program.dart new file mode 100644 index 0000000..6a19d35 --- /dev/null +++ b/bin/run_main_program.dart @@ -0,0 +1,56 @@ +import 'dart:io'; + +import 'package:args/args.dart'; +import 'package:hive/hive.dart'; + +import 'ean_products_2_csv.dart'; +import 'models/hive_product.dart'; +import 'read_ean_products.dart'; +import 'specific/s_kaupat/ean_handler.dart'; +import 'specific/s_kaupat/read_receipt_products.dart'; +import 'specific/s_kaupat/receipt_products_2_csv.dart'; +import 'utils/arg_selector_helper.dart'; +import 'utils/printing_helper.dart'; +import 'utils/shop_selector_helper.dart'; + +Future> runMainProgram( + ArgResults argResults, Box hiveProducts) async { + print('\nRunning...\n'); + + var selectedTextFile = argResults[ArgSelector.textFile.value] as String?; + var selectedHtmlFile = argResults[ArgSelector.htmlFile.value] as String; + var selectedStore = argResults[ArgSelector.foodOnlineStore.value] as String; + var csvFilesPath = argResults[ArgSelector.csvPath.value] as String; + + printSelectedValues( + selectedTextFile, selectedHtmlFile, selectedStore, csvFilesPath); + + try { + if (ShopSelector.sKaupat.value == selectedStore) { + var receiptProducts = + await readReceiptProducts(selectedTextFile!, csvFilesPath); + var eanProducts = await readEANProducts( + selectedHtmlFile, ShopSelector.sKaupat, csvFilesPath); + + await eanHandler(receiptProducts, eanProducts.toList(), hiveProducts); + + receiptProducts2CSV(receiptProducts, csvFilesPath); + eanProducts2CSV(eanProducts, csvFilesPath, ShopSelector.sKaupat.name); + } else if (ShopSelector.kRuoka.value == selectedStore) { + var eanProducts = await readEANProducts( + selectedHtmlFile, ShopSelector.kRuoka, csvFilesPath); + + eanProducts2CSV(eanProducts, csvFilesPath, ShopSelector.kRuoka.name); + } else { + print('Unknown store: $selectedStore'); + exitCode = 1; + } + } on Exception catch (e) { + print('Error: $e'); + exitCode = 1; + } + + print('\nDone!'); + + return hiveProducts; +} diff --git a/bin/specific/s_kaupat/ean_handler.dart b/bin/specific/s_kaupat/ean_handler.dart index 232362d..1103a0c 100644 --- a/bin/specific/s_kaupat/ean_handler.dart +++ b/bin/specific/s_kaupat/ean_handler.dart @@ -7,16 +7,12 @@ import '../../models/hive_product.dart'; import '../../models/receipt_product.dart'; import '../../utils/ansipen_helper.dart'; -const _kHiveBoxName = 'hiveProducts'; - -/// Handles the EAN products. -Future eanHandler( - List receiptProducts, List eanProducts) async { +/// Handles the EAN products using Hive storage. +Future> eanHandler(List receiptProducts, + List eanProducts, Box hiveProducts) async { List nonFoundReceiptProducts = []; List nonFoundReceiptProducts2 = []; - Box hiveProducts = await _initializeHiveProducts(); - print('\nThe first round begins!'); print('Statistics:'); print(peachPen().write('Amount of hive products: ${hiveProducts.length}')); @@ -33,7 +29,7 @@ Future eanHandler( var filteredEanProducts = _filterEANProducts(receiptProduct.name, eanProducts, eanProductName); - _handleFoundCases( + await _handleFoundCases( receiptProduct, filteredEanProducts, eanProducts, hiveProducts); print(peachPen().write('Amount of hive products: ${hiveProducts.length}')); @@ -66,7 +62,7 @@ Future eanHandler( var filteredEanProducts = _filterEANProducts( splittedReceiptProcuctNames[0], eanProducts, eanProductName); - _handleFoundCases( + await _handleFoundCases( nonFoundReceiptProduct, filteredEanProducts, eanProducts, hiveProducts); if (filteredEanProducts.isEmpty) { @@ -82,7 +78,7 @@ Future eanHandler( 'left.'); print(peachPen().write('Amount of hive products: ${hiveProducts.length}')); - hiveProducts.close(); + return hiveProducts; } String? _filterHiveProducts( @@ -104,12 +100,6 @@ String? _filterHiveProducts( return eanProductName; } -Future> _initializeHiveProducts() async { - Hive.init(Directory.current.path); - Hive.registerAdapter(HiveProductAdapter()); - return await Hive.openBox(_kHiveBoxName); -} - List _filterEANProducts(String receiptProductName, List eanProducts, String? eanProductName) { /* @@ -129,11 +119,11 @@ List _filterEANProducts(String receiptProductName, .toList(); } -void _handleFoundCases( +Future _handleFoundCases( ReceiptProduct receiptProduct, List filteredEanProducts, List origEanProducts, - Box hiveProducts) { + Box hiveProducts) async { if (filteredEanProducts.length == 1) { print(greenPen().write('\tFound one product:')); print('\t\t${filteredEanProducts.first}'); @@ -159,7 +149,7 @@ void _handleFoundCases( receiptProduct.eanCode = selectedEanProduct.ean; - hiveProducts.add(HiveProduct( + await hiveProducts.add(HiveProduct( receiptName: receiptProduct.name, eanName: selectedEanProduct.name)); print( peachPen().write('Amount of hive products: ${hiveProducts.length}')); diff --git a/bin/specific/s_kaupat/strings_to_receipt_products.dart b/bin/specific/s_kaupat/strings_to_receipt_products.dart index c965523..3828c83 100644 --- a/bin/specific/s_kaupat/strings_to_receipt_products.dart +++ b/bin/specific/s_kaupat/strings_to_receipt_products.dart @@ -88,7 +88,7 @@ List strings2ReceiptProducts(List rows) { lastProduct.totalPrice = fixedPriceAsString; } // If a row starts with a digit, it is a quantity and price per unit row: - else if (item.contains(RegExp(r'^\d'))) { + else if (item.startsWith(RegExp(r'^\d+\s{1}kpl'))) { var items = item.split(RegExp(r'\s{6,7}')); var quantity = items[0].substring(0, 2).trim().replaceAll(RegExp(r','), '.'); diff --git a/bin/utils/arg_selector_helper.dart b/bin/utils/arg_selector_helper.dart index aace76e..098652e 100644 --- a/bin/utils/arg_selector_helper.dart +++ b/bin/utils/arg_selector_helper.dart @@ -5,7 +5,8 @@ enum ArgSelector { foodOnlineStore('store'), csvPath('csv'), help('help'), - run('run'); + run('run'), + hive('hive'); final String term; const ArgSelector(this.term); diff --git a/bin/utils/extensions/string_extension.dart b/bin/utils/extensions/string_extension.dart new file mode 100644 index 0000000..2ccdabe --- /dev/null +++ b/bin/utils/extensions/string_extension.dart @@ -0,0 +1,12 @@ +/// Extends the [String] class with some useful methods. +extension StringExtension on String? { + /// Checks if the string is null or empty. + bool isNullOrEmpty() { + return this == null || this!.isEmpty; + } + + /// Checks if the string is not null or empty. + bool isNotNullOrEmpty() { + return this != null && this!.isNotEmpty; + } +} diff --git a/bin/utils/parse_kassakuitti_arguments.dart b/bin/utils/parse_kassakuitti_arguments.dart index a8b21c2..eef6b3e 100644 --- a/bin/utils/parse_kassakuitti_arguments.dart +++ b/bin/utils/parse_kassakuitti_arguments.dart @@ -5,6 +5,8 @@ import 'shop_selector_helper.dart'; ArgParser getParser() { final parser = ArgParser() + ..addCommand(ArgSelector.help.value) + ..addCommand(ArgSelector.hive.value) ..addCommand(ArgSelector.run.value) ..addOption( ArgSelector.textFile.value, @@ -27,8 +29,7 @@ ArgParser getParser() { ArgSelector.csvPath.value, abbr: ArgSelector.csvPath.value.substring(0, 1), help: 'Path for output CSV files', - ) - ..addCommand(ArgSelector.help.value); + ); return parser; } diff --git a/bin/utils/printing_helper.dart b/bin/utils/printing_helper.dart index a24aeca..085700b 100644 --- a/bin/utils/printing_helper.dart +++ b/bin/utils/printing_helper.dart @@ -4,6 +4,7 @@ import 'package:args/args.dart'; import 'package:path/path.dart'; import 'package:yaml/yaml.dart'; +/// Prints selected values. void printSelectedValues(String? selectedTextFile, String selectedHtmlFile, String selectedStore, String csvFilesPath) { print('Selected values:' @@ -13,6 +14,7 @@ void printSelectedValues(String? selectedTextFile, String selectedHtmlFile, '\n- Path where to save CSV files:\t\t$csvFilesPath\n'); } +/// Prints some basic info. Future printBasicInfo(ArgParser parser) async { String pathToYaml = join(dirname(Platform.script.toFilePath()), '../pubspec.yaml'); @@ -23,7 +25,19 @@ Future printBasicInfo(ArgParser parser) async { print(yaml['name']); print(yaml['description']); print('Version: ${yaml['version']}'); - print('Homepage: ${yaml['homepage']}'); + print('Homepage: ${yaml['homepage']}\n'); - print('\nHelp:\n${parser.usage}'); + printHelpers(parser); +} + +/// Prints helpers. +void printHelpers(ArgParser parser) { + print('Available commands:'); + parser.commands.forEach((name, command) { + print(' $name'); + }); + + print('\n----\n'); + + print('Run usages:\n${parser.usage}'); } diff --git a/pubspec.lock b/pubspec.lock index 7c87edd..68c89ca 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -7,14 +7,14 @@ packages: name: _fe_analyzer_shared url: "https://pub.dartlang.org" source: hosted - version: "38.0.0" + version: "40.0.0" analyzer: dependency: transitive description: name: analyzer url: "https://pub.dartlang.org" source: hosted - version: "3.4.1" + version: "4.1.0" ansicolor: dependency: "direct main" description: @@ -28,7 +28,7 @@ packages: name: args url: "https://pub.dartlang.org" source: hosted - version: "2.3.0" + version: "2.3.1" async: dependency: transitive description: @@ -63,14 +63,14 @@ packages: name: build_resolvers url: "https://pub.dartlang.org" source: hosted - version: "2.0.8" + version: "2.0.9" build_runner: dependency: "direct dev" description: name: build_runner url: "https://pub.dartlang.org" source: hosted - version: "2.1.10" + version: "2.1.11" build_runner_core: dependency: transitive description: @@ -91,14 +91,7 @@ packages: name: built_value url: "https://pub.dartlang.org" source: hosted - version: "8.2.0" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.1" + version: "8.3.2" checked_yaml: dependency: transitive description: @@ -126,28 +119,28 @@ packages: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.15.0" + version: "1.16.0" convert: dependency: transitive description: name: convert url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.0.2" crypto: dependency: transitive description: name: crypto url: "https://pub.dartlang.org" source: hosted - version: "3.0.1" + version: "3.0.2" csslib: dependency: transitive description: name: csslib url: "https://pub.dartlang.org" source: hosted - version: "0.17.1" + version: "0.17.2" dart_style: dependency: transitive description: @@ -168,14 +161,14 @@ packages: name: fixnum url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.1" frontend_server_client: dependency: transitive description: name: frontend_server_client url: "https://pub.dartlang.org" source: hosted - version: "2.1.2" + version: "2.1.3" glob: dependency: transitive description: @@ -196,14 +189,14 @@ packages: name: hive url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.2.2" hive_generator: dependency: "direct dev" description: name: hive_generator url: "https://pub.dartlang.org" source: hosted - version: "1.1.2" + version: "1.1.3" html: dependency: "direct main" description: @@ -224,7 +217,7 @@ packages: name: http_parser url: "https://pub.dartlang.org" source: hosted - version: "4.0.0" + version: "4.0.1" intl: dependency: "direct main" description: @@ -252,7 +245,7 @@ packages: name: json_annotation url: "https://pub.dartlang.org" source: hosted - version: "4.4.0" + version: "4.5.0" lints: dependency: "direct dev" description: @@ -280,14 +273,14 @@ packages: name: meta url: "https://pub.dartlang.org" source: hosted - version: "1.7.0" + version: "1.8.0" mime: dependency: transitive description: name: mime url: "https://pub.dartlang.org" source: hosted - version: "1.0.1" + version: "1.0.2" package_config: dependency: transitive description: @@ -301,7 +294,7 @@ packages: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.8.2" pool: dependency: transitive description: @@ -357,7 +350,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.9.0" stack_trace: dependency: transitive description: @@ -385,7 +378,7 @@ packages: name: string_scanner url: "https://pub.dartlang.org" source: hosted - version: "1.1.0" + version: "1.1.1" term_glyph: dependency: transitive description: @@ -406,7 +399,7 @@ packages: name: typed_data url: "https://pub.dartlang.org" source: hosted - version: "1.3.0" + version: "1.3.1" watcher: dependency: transitive description: @@ -420,13 +413,13 @@ packages: name: web_socket_channel url: "https://pub.dartlang.org" source: hosted - version: "2.1.0" + version: "2.2.0" yaml: dependency: "direct main" description: name: yaml url: "https://pub.dartlang.org" source: hosted - version: "3.1.0" + version: "3.1.1" sdks: - dart: ">=2.17.1 <3.0.0" + dart: ">=2.17.3 <3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index b0f8a2f..2e97cc1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,27 +1,27 @@ name: dart_kassakuitti_cli description: A simple Dart CLI app to handle a cash receipt coming from S-kaupat or K-ruoka (two Finnish food online stores). -version: 0.14.0 +version: 0.15.0 homepage: https://github.com/areee/dart_kassakuitti_cli environment: - sdk: '>=2.17.1 <3.0.0' + sdk: '>=2.17.3 <3.0.0' # dependencies: # path: ^1.8.0 dev_dependencies: - build_runner: ^2.1.10 - hive_generator: ^1.1.2 + build_runner: ^2.1.11 + hive_generator: ^1.1.3 lints: ^2.0.0 dependencies: ansicolor: ^2.0.1 - args: ^2.3.0 - hive: ^2.1.0 + args: ^2.3.1 + hive: ^2.2.2 html: ^0.15.0 intl: ^0.17.0 - path: ^1.8.1 - yaml: ^3.1.0 + path: ^1.8.2 + yaml: ^3.1.1 assets: - assets/files/ \ No newline at end of file