Bodega Stocks ============= Given information about the stocks currently available in a "bodega" we wish to process the daily orders received. Both data are saved in text files: the *current stocks* file and the *daily orders* file. The following conventions apply: - All file names have the ``.txt`` extension. - All file contents have not header line and have lines with same data items separated by ``','``. - All dates appearing below have an 8-character format ``'dd-mm-yy'`` where ``dd`` are two digits denoting the day of the month, ``mm`` are two digits with the month number, and ``aa`` are two digits with the year. The details of their contents are the following: #. The **stocks file** has a number of lines corresponding to products in the *bodega*'s stock. Each line is composed of three items of a product: - the *Product Identification Code* **PIC** (:class:`str`) - the **quantity** available (:class:`float`) - the last **date** of the quantity update (:class:`str`) .. note:: There is one line for each PIC **at most**. For example: .. literalinclude:: stocks.txt :language: python3 This file can be downloaded from: :download:`stocks.txt`. #. The **daily orders file** contains a number of lines corresponding to orders placed a given date. Each line is composed of two items of an order: - a :class:`str` with the *PIC* - a :class:`float` of the quantity requested by the order .. note:: There can be more than one order with the same PIC. For example: .. literalinclude:: orders-01-12-24.txt :language: python This file can be downloaded from: :download:`orders-01-12-24.txt`. In this context, you are required to deliver the following functions in the module :mod:`stocks` (file :file:`stocks.py`). First there is the main function specification followed by ome subfunctions. Following the steps below is strongly recommended: #. Read all function specifications. #. Start coding the main one (the first one) bearing the subfunctions in mind. #. Code and Test the subfunctions. #. Test the main function. #. Deliver all functions in the above indicated file. ------------------------------------------------------------------------------------------------ The main function is: .. py:function:: stock_update(stkFn, ordFn, date): such that **given** - *stkFn*, *ordFn*, two :class:`str` with the names of the stocks and orders files as described above - a :class:`str` with a *date* (with the format specified above) **writes** two textfiles, both with the ``'.txt'`` extension: - A file called word ``'stocks'`` concatenated with a ``'-'`` to the *date* and the ``'.txt'`` extension. This file must have a line for each product in *stkFn* modified as follows: - the quantity as been updated by substracting the quantities of the correct orders in *ordFn*. - if the quantity has changed then the date has also been changed to the current date. - a file called word ``'errors'`` concatenated with a ``'-'`` to the *date* and the ``'.txt'`` extension. This file must have a line for each error produced while processing the orders in *ordFn*. The line must have a :class:`str` with the error code followed by ``' : '`` and the order informations separated by ``','``. The error codes to consider are the following: - ``'OrderError'`` if the order has not exactly two items: the PIC and the quantity. - ``'ProdNotFoundError'`` if the order refers to a product not included in the stocks file. - ``'StockNotEnoughError'`` if the quantity of the order is bigger that the stock quantity of that product in the stocks file. **returns** two integers: the number of orders successfully processed and the number of errors produced. For example, *stock_update* applied to the previous input files would return the values ``(5, 5)`` and write two files called ``stocks-01-12-24.txt`` and ``errors-01-12-24.txt`` with the following contents: .. literalinclude:: stocks-01-12-24.ref :language: python .. literalinclude:: errors-01-12-24.ref :language: python .. note:: Observe that if a product receives more than one order, the orders that do not exceed the product stock are properly served, the quantity available is updates and no error is raised. The error is produced when an order request an quantity higher that the quantity available only without affecting the previous orders for that product. Doctests are available in the :download:`stock_update.test` file. To pass these doctests you need the :download:`stocks.txt` file as well as the files in the following zip file: :download:`stocks_refs.zip`. ------------------------------------------------------------------------------------------------ The first subfunction is: .. py:function:: gen_stkD(stkFn) such that **given** *stkFn* a :class:`str` with the name of a stocks file as described above **returns** a :class:`dict` where the key is a :class:`str` with the Product Identification Code (PIC) and the associated value is a two-component :class:`tuple`: a :class:`tuple` with the product's quantity available in stock and a :class:`str` with the date of the last update date of that quantity. For example, given the stocks file shown above .. literalinclude:: stocks.txt :language: python3 we should have: .. literalinclude:: gen_stkD.test :language: python3 :start-after: --ini :end-before: --fi Doctests are available in the :download:`gen_stkD.test` file. To pass these doctests you may need to download the stocks file: :download:`stocks.txt`. ------------------------------------------------------------------------------------------------ The second subfunction is: .. py:function:: upd_stkD(stkD, ordFn, date) such that **given** - *stkD*, a :class:`dict` like the one produced by the previous function *gen_stkD* - *ordFn* the name of a stocks file as described above - *date* a :class:`str` with a date (in the format specified above) **updates** *stkD* according to the orders in *ordFn* **writes** a new *errors* textfile as described in the *stock_update* function above **returns** two integers: the number of orders successfully processed and the number of errors produced. For example, given the :class:`dict` from the previous example: .. literalinclude:: upd_stkD.test :language: python3 :start-after: --inidict :end-before: --fidict and the ``orders-01-12-24.txt`` file above: .. literalinclude:: orders-01-12-24.txt :language: python the following call: .. literalinclude:: upd_stkD.test :language: python3 :start-after: --inicall :end-before: --ficall should have the following three outcomes: #. update the *stkD* :class:`dict` as follows (notice that both the quantities and the last date update are affected), .. literalinclude:: upd_stkD.test :language: python3 :start-after: --inisol :end-before: --fisol #. return the :class:`tuple` ``(5, 5)``, and #. write a new file named ``'errors-01-12-24.txt'`` with the following contents: .. literalinclude:: errors-01-12-24.txt :language: python Doctests are available in the :download:`upd_stkD.test` file. To pass these doctests you may need to download the following file: :download:`errors-01-12-24.ref`. ------------------------------------------------------------------------------------------------ The third subfunction is: .. py:function:: write_stkD(stkD, date) such that **given** - *stkD* a :class:`dict` as the one produced by the previous function *gen_stkD* - *date* a :class:`str` with a date (in the format specified above) **writes** **writes** a new *stocks* textfile as described in the *stock_update* function above. For example, given the following call .. literalinclude:: write_stkD.test :language: python3 :start-after: --ini :end-before: --fi should not change the *stkD* :class:`dict` at all, and a new file named ``'stocks-01-12-24.txt'`` should be written with the following contents: .. literalinclude:: stocks-01-12-24.txt :language: python Doctests are available in the :download:`write_stkD.test` file. To pass these doctests you may need to download the following file: :download:`stocks-01-12-24.ref`.