General overview of Lino Shop

The goal of Lino Shop is

A tested document

This is a tested document. The following instructions are used for initialization:

>>> import lino
>>> lino.startup('lino_shop.projects.shop1.settings')
>>> from lino.api.doctest import *

webshop uses the following action specifier, which works only since 2021-03-19:

>>> from lino.core.actors import resolve_action
>>> resolve_action('shopping.MyCart.start_plan')
<BoundAction(shopping.MyCart, <lino.modlib.users.mixins.StartPlan start_plan>)>

Before 2021-03-19, resolve_action() used rt.models.resolve(), which returned the unbound action object, and then bound it to its defining actor, which is not lino_xl.lib.shopping.MyCart but lino_xl.lib.sheets.Reports (the first actor that happens to use the lino.modlib.users.StartPlan action). So this pitfall was only when your application had multiple subclasses of UserPlan that do not override the start_plan action.

>>> x = rt.models.resolve('shopping.MyCart.start_plan')
>>> x
<lino.modlib.users.mixins.StartPlan start_plan>
>>> x.defining_actor
lino_xl.lib.shopping.models.Carts
>>> rt.show(memo.Mentions)
====================================== =====================================================
 Source                                 Controlled by
-------------------------------------- -----------------------------------------------------
 *Storm island cover*                   *Eye of the Needle*
 *And then there were none*             *And then there were None*
 *Murder on the orient express cover*   *Murder on the Orient Express (Hercule Poirot #10)*
====================================== =====================================================

Using remote virtual fields in a detail view

It seems that the lino.modlib.uploads.Upload.thumbnail field was the first case of a remote virtual field being used in a detail window. In that case, lino.core.store.Store.row2dict() didn’t fill the correct key names. The following snippets were used to verify this. But they don’t apply any more after 20230125 because we removed FileUsage model.

>>> row = uploads.Upload.objects.first()
>>> ar = rt.login('robin').spawn(uploads.Uploads)
>>> ah = uploads.Uploads.get_handle()
>>> pprint(ah.store.row2dict(ar, row))  
{'description': 'Murder on the orient express cover',
 'disable_editing': False,
 'disabled_fields': {'file_size': True, 'id': True, 'mimetype': True},
 'file': 'uploads/2021/03/MurderontheOrientExpress.jpg',
 'id': 1,
 'library_file': '',
 'owner': '',
 'preview': '<img src="/media/uploads/2021/03/MurderontheOrientExpress.jpg" '
            'style="max-width: 100%; max-height: 20em">',
 'type': None,
 'typeHidden': None,
 'upload_area': 'General',
 'upload_areaHidden': '90',
 'user': None,
 'userHidden': None,
 'volume': None,
 'volumeHidden': None}

Here are all the other store fields using by the detail of lino.modlib.uploads.Uploads:

>>> for sf in ah.store.detail_fields:
...     print(sf)
FileFieldStoreField 'file'
ForeignKeyStoreField 'user'
ForeignKeyStoreField 'volume'
StoreField 'library_file'
ComboStoreField 'upload_area'
ForeignKeyStoreField 'type'
StoreField 'description'
GenericForeignKeyField 'owner'
(virtual)DisplayStoreField 'preview'
AutoStoreField 'id'
ForeignKeyStoreField 'type'
StoreField 'description'
FileFieldStoreField 'file'
ForeignKeyStoreField 'volume'
StoreField 'library_file'
ForeignKeyStoreField 'user'
AutoStoreField 'id'
DisabledFieldsStoreField 'disabled_fields'
DisableEditingStoreField 'disable_editing'

Here is a list of all remote virtual fields used in Lino Shop:

>>> for a, sf in walk_store_fields():
...     if "__" in sf.name:
...         print(a, sf, sf.field)  
products.Things StoreField 'product__name' products.Product.name
products.Things StoreField 'product__name' products.Product.name
products.Things ComboStoreField 'product__product_type' products.Product.product_type
products.Things ForeignKeyStoreField 'product__category' products.Product.category
products.Things ComboStoreField 'product__delivery_unit' products.Product.delivery_unit
products.Things StoreField 'product__body' products.Product.body
products.Furniture StoreField 'product__name' products.Product.name
products.Furniture StoreField 'product__name' products.Product.name
products.Furniture ComboStoreField 'product__product_type' products.Product.product_type
products.Furniture ForeignKeyStoreField 'product__category' products.Product.category
products.Furniture ComboStoreField 'product__delivery_unit' products.Product.delivery_unit
products.Furniture StoreField 'product__body' products.Product.body
products.Books StoreField 'product__name' products.Product.name
products.Books StoreField 'product__name' products.Product.name
products.Books ComboStoreField 'product__product_type' products.Product.product_type
products.Books ForeignKeyStoreField 'product__category' products.Product.category
products.Books ComboStoreField 'product__delivery_unit' products.Product.delivery_unit
products.Books StoreField 'product__body' products.Product.body
vat.MovementsByDeclaration ComboStoreField 'account__vat_column' ledger.Account.vat_column
trading.DueInvoices StoreField 'journal__ref' ledger.Journal.ref
trading.InvoiceItemsByProduct ForeignKeyStoreField 'voucher__partner' trading.VatProductInvoice.partner

TODO: sales.DueInvoices StoreField ‘journal__ref’ is another example of a remote virtual field being used in a detail window. Explain why the problem never occurred before .