ผลต่างระหว่างรุ่นของ "Multi-component Page"

จาก คูนิฟ็อกซ์ วิกิ
บรรทัดที่ 45: บรรทัดที่ 45:
* '''proceed_lock_seq''' ''([[str,],]: defaults to {{code|lang=python|[]}})'': List of document verification items that should prevent proceeding/canceling away from each sequence.
* '''proceed_lock_seq''' ''([[str,],]: defaults to {{code|lang=python|[]}})'': List of document verification items that should prevent proceeding/canceling away from each sequence.
* '''searchers''' ''[CuneiTable,]: defaults to {{code|lang=python|[]}}'': List of search tables.
* '''searchers''' ''[CuneiTable,]: defaults to {{code|lang=python|[]}}'': List of search tables.
<syntaxhighlight lang="python">
# Example from Accounting Journal (w/ Input VAT) page
# MAIN SEQUENCE FORMS/TABLES
head_form = VoucherHeadForm.init_form(prefix="VoucherHeadForm",
                                gen_del="cunei_gl", sequence_bound=True,
                                populate_id=["id"], populate_suppress=["grab"],
                                post_route=url_for("<head_submit_route>"), ...)
vouch_tb = VouchBodyTable(prefix="VouchBodyTable", editable=True, perm_bit=4,
                        populate_route=url_for("<vouch_default_val_request_route>"),
                        populate_id=["master.id"], populate_suppress=["qsch", "free_grab"],
                        post_route=url_for("<vouch_submit_route>"), ...)
vouchsum_form = VoucherDetailSum.init_form(prefix="VoucherDetailSum", ...)
vat_tb = VouchVatTable(prefix="VouchVatTable", editable=True, perm_bit=4,
                        populate_route=url_for("<vat_default_val_request_route>"),
                        populate_id=["master.id", "#master.section_stid",
                                    "#master.docdate", "#master.desc"],
                        populate_suppress=["qsch", "free_grab"],
                        post_route=url_for("<vat_submit_route>"), ...)
vatsum_form = VatDetailSum.init_form(prefix="VatDetailSum", ...)
wht_tb = VouchWhtTable(prefix="VouchWhtTable", editable=True, perm_bit=4,
                        populate_route=url_for("<wht_default_val_request_route>"),
                        populate_id=["master.id", "#master.section_stid",
                                    "#master.docdate", "#master.desc"],
                        populate_suppress=["qsch", "free_grab"],
                        post_route=url_for("<wht_submit_route>"), ...)
whtsum_form = WhtDetailSum.init_form(prefix="WhtDetailSum", ...)
# SEARCH TABLES
# (Note that most search tables use unified 'Search Table with a Stand-alone Page'.
#  See corresponding section under CuneiTable page for the template.)
section_tb = SectionTable(prefix="SectionTable", perm_bit=<user_perm_for_section>,
            populate_route=url_for("cunei_gl.section", fetch="yes"),
            post_route=url_for("cunei_gl.section"),
            in_modal="Modal0", modal_head=lazy_gettext("Choose Section"), ...)
acccode_tb = AccCodeTable(prefix="AccCodeTable", perm_bit=<user_perm_for_acccode>,
            populate_route=url_for("cunei_gl.acccode", fetch="yes"),
            post_route=url_for("cunei_gl.acccode"),
            in_modal="Modal1", modal_head=lazy_gettext("Choose Account Code"), ...)
...
# START CREATING DOCUMENT CONTEXT
mainseq = [[head_form],
          [vouch_tb, vat_tb, wht_tb, vouchsum_form, vatsum_form, whtsum_form]]
attach_form = StdAttachForm.gen_attach_form(post_route=url_for("<attach_submit_route>"),
                                            populate_route=url_for("<attach_fetch_route>"))
modalprint_form = StdModalPrintForm.gen_modalprint_form(post_route=url_for("<custom_prn_submit_route>"))
modaldel_form = StdModalDelForm.gen_modaldel_form(post_route=url_for("<mass_del_submit_route>"))
modalcopy_form = StdCopyForm.gen_copy_form(url_for("<copy_submit_route>"), ...),
modalimport_form = StdImportForm.gen_import_form(url_for("<import_route>"))
# USE 'pack_mainseq' TO FILL UNSPECIFIED KEYS WITH DEFAULT VALUES.
mainseq_args = pack_mainseq(mainseq=mainseq,
                            mainseq_add="newmaster",
                            mainseq_del="delmaster",
                            page_perm=<user_perm_for_the_page>,
                            mainseq_proceed=["submit", "beacon"],
                            proceed_lock_seq=[[], ["incomp"]],
                            mainseq_search="docno",
                            mainseq_print=url_for("<print_route>"),
                            mainseq_export=url_for("<export_route>"),
                            mainseq_beacon=url_for("<beacon_route>"),
                            mainseq_copy=modalcopy_form,
                            mainseq_attach=attach_form,
                            mainseq_modalprint=modalprint_form,
                            mainseq_modaldel=modaldel_form,
                            mainseq_upload=modalimport_form,
                            searchers=[section_tb, acccode_tb, ...])
</syntaxhighlight>


==== Page Sequence ====
==== Page Sequence ====

รุ่นแก้ไขเมื่อ 14:14, 28 มิถุนายน 2567

While CuneiForms and CuneiTables on each of their own can create functional pages for several purposes, most accounting and transaction records require both to be displayed and manipulated in a meaningful manner. And while it is possible for such pages to be perfectly functional by stringing stad-alone forms and tables together, the numbers of requests and database accesses are unnecessarily high.

In the CuneiFox framework, inter-related forms and tables can be linked together via the use of Document Context. Below are the key functions of Document Context:

  • Control page-level permissions and operations.
  • Perform a document-lock/unlock upon entering entering/exiting the page's edit mode.
  • Consolidate populating request for all forms and tables on the page.
  • String together page edit sequence.

Define a Document Context

Document Context is a dict fed to the Flask render_template function. Most of the keys in the dict are handled (with default values assigned, if not given) by a separate Python function prep_mainseq. We shall begin with these so-called Main Sequence keys, then we will discuss a few additional keys.

Main Sequence Keys

  • page_perm (int: defaults to 1): Page-level permission value.
    • 0: Not readable. (Usually users with this permission level should be prevented from reaching the page at all. DO NOT rely on this permission bit as a security measure,)
    • 1: Read-only.
    • 2: Add. (Allows 'add' type actions: add and copy.)
    • 3: Add + Edit.
    • 4: Add + Edit + Delete.
    • ≥5: Add + Edit + Delete + Import.
  • mainseq ([[CuneiForm/CuneiTable,],]: defaults to []): The list of page sequence specifications. Each member is a list of CuneiForms and/or CuneiTables belonging to that specific sequence.
  • mainseq_name ([[str,],]: defaults to []): Basically mainseq, but repacked with _id attributes (str) of each CuneiForm/CuneiTable in place of the object itself. (This value is automatically created can only used for ease of internal references.)
  • mainseq_add (str: defaults to 'plain'): Action type when the page-level Add button is clicked.
    • 'newmaster': The button triggers the addition of a new master entry. (This setting assumes the existence of a Master Form and certain Mass Populate setting.)
    • Any other string: The button triggers the function this_page_add(event). This function must be custom written for each page that needs it.
  • mainseq_del (str: defaults to 'plain'): Action type when the page-level Delete button is clicked.
    • 'delmaster': The button triggers the prompt for the deletion of the current master entry. (This setting assumes the existence of a Master Form and certain Mass Populate setting.)
    • Any other string: The button triggers the function this_page_delete(event). This function must be custom written for each page that needs it.
  • mainseq_modaldel (CuneiForm: defaults to False): If defined, right-clicking on the page-level Delete button triggers a CuneiModal containing this form. The standard Mass Deletion Form is pre-defined at cuneifox.base.main.forms.StdModalDelForm.
  • mainseq_proceed ([str,]: defaults to []): Each sequence's action type when the page-level Proceed button is clicked.
    • 'submit': Submit the first CuneiForm in the current page sequence.
    • 'beacon': Beam a 'proceed' beacon to the server to signal a page sequence change. (For the final page sequence, a 'cancel' beacon is sent instead to signal checking out of the page's edit mode.)
  • mainseq_beacon (url_for_string: defaults to False): Route for beacon transmission.
  • mainseq_search (str: defaults to False): Field name of the Master Form used for page-level search.
  • mainseq_schprmpt (str: defaults to 'Document Number'): Prompt text for page-level search.
  • mainseq_copy (CuneiForm: defaults to False): If defined, clicking on the page-level Copy button triggers a CuneiModal containing this form. The standard Document Copy Form is pre-defined at cuneifox.base.main.forms.StdCopyForm.
  • mainseq_attach (CuneiForm: defaults to False): If defined, clicking on the page-level Attach button triggers a CuneiModal containing this form. The standard Document Attach Form is pre-defined at cuneifox.base.main.forms.StdAttachForm.
  • mainseq_print (url_for_string: defaults to False): Route for print request.
  • mainseq_modalprint (CuneiForm: defaults to False): If defined, right-clicking on the page-level Print button triggers a CuneiModal containing this form. The standard Custom Printing Form is pre-defined at cuneifox.base.main.forms.StdModalPrintForm.
  • mainseq_qr (url_for_string: defaults to False): Route for Payment QR-code request.
  • mainseq_vouch (url_for_string: defaults to False): Route to corresponding Accounting Journal record. (Usually directed through cunei_gl.direct_to_vouch.)
  • mainseq_upload (CuneiForm: defaults to False): If defined, clicking on the page-level Import button triggers a CuneiModal containing this form. The standard Document Import Form is pre-defined at cuneifox.base.main.forms.StdImportForm.
  • mainseq_export (url_for_string: defaults to False): Route to export request.
  • proceed_lock_seq ([[str,],]: defaults to []): List of document verification items that should prevent proceeding/canceling away from each sequence.
  • searchers [CuneiTable,]: defaults to []: List of search tables.
# Example from Accounting Journal (w/ Input VAT) page

# MAIN SEQUENCE FORMS/TABLES
head_form = VoucherHeadForm.init_form(prefix="VoucherHeadForm",
                                gen_del="cunei_gl", sequence_bound=True,
                                populate_id=["id"], populate_suppress=["grab"],
                                post_route=url_for("<head_submit_route>"), ...)
vouch_tb = VouchBodyTable(prefix="VouchBodyTable", editable=True, perm_bit=4,
                        populate_route=url_for("<vouch_default_val_request_route>"),
                        populate_id=["master.id"], populate_suppress=["qsch", "free_grab"],
                        post_route=url_for("<vouch_submit_route>"), ...)
vouchsum_form = VoucherDetailSum.init_form(prefix="VoucherDetailSum", ...)
vat_tb = VouchVatTable(prefix="VouchVatTable", editable=True, perm_bit=4,
                        populate_route=url_for("<vat_default_val_request_route>"),
                        populate_id=["master.id", "#master.section_stid",
                                     "#master.docdate", "#master.desc"],
                        populate_suppress=["qsch", "free_grab"],
                        post_route=url_for("<vat_submit_route>"), ...)
vatsum_form = VatDetailSum.init_form(prefix="VatDetailSum", ...)
wht_tb = VouchWhtTable(prefix="VouchWhtTable", editable=True, perm_bit=4,
                        populate_route=url_for("<wht_default_val_request_route>"),
                        populate_id=["master.id", "#master.section_stid", 
                                     "#master.docdate", "#master.desc"],
                        populate_suppress=["qsch", "free_grab"],
                        post_route=url_for("<wht_submit_route>"), ...)
whtsum_form = WhtDetailSum.init_form(prefix="WhtDetailSum", ...)

# SEARCH TABLES
# (Note that most search tables use unified 'Search Table with a Stand-alone Page'.
#  See corresponding section under CuneiTable page for the template.)
section_tb = SectionTable(prefix="SectionTable", perm_bit=<user_perm_for_section>,
            populate_route=url_for("cunei_gl.section", fetch="yes"),
            post_route=url_for("cunei_gl.section"),
            in_modal="Modal0", modal_head=lazy_gettext("Choose Section"), ...)
acccode_tb = AccCodeTable(prefix="AccCodeTable", perm_bit=<user_perm_for_acccode>,
            populate_route=url_for("cunei_gl.acccode", fetch="yes"),
            post_route=url_for("cunei_gl.acccode"),
            in_modal="Modal1", modal_head=lazy_gettext("Choose Account Code"), ...)
...

# START CREATING DOCUMENT CONTEXT
mainseq = [[head_form],
           [vouch_tb, vat_tb, wht_tb, vouchsum_form, vatsum_form, whtsum_form]]
attach_form = StdAttachForm.gen_attach_form(post_route=url_for("<attach_submit_route>"),
                                            populate_route=url_for("<attach_fetch_route>"))
modalprint_form = StdModalPrintForm.gen_modalprint_form(post_route=url_for("<custom_prn_submit_route>"))
modaldel_form = StdModalDelForm.gen_modaldel_form(post_route=url_for("<mass_del_submit_route>"))
modalcopy_form = StdCopyForm.gen_copy_form(url_for("<copy_submit_route>"), ...),
modalimport_form = StdImportForm.gen_import_form(url_for("<import_route>"))

# USE 'pack_mainseq' TO FILL UNSPECIFIED KEYS WITH DEFAULT VALUES.
mainseq_args = pack_mainseq(mainseq=mainseq,
                            mainseq_add="newmaster",
                            mainseq_del="delmaster",
                            page_perm=<user_perm_for_the_page>,
                            mainseq_proceed=["submit", "beacon"],
                            proceed_lock_seq=[[], ["incomp"]],
                            mainseq_search="docno",
                            mainseq_print=url_for("<print_route>"),
                            mainseq_export=url_for("<export_route>"),
                            mainseq_beacon=url_for("<beacon_route>"),
                            mainseq_copy=modalcopy_form,
                            mainseq_attach=attach_form,
                            mainseq_modalprint=modalprint_form,
                            mainseq_modaldel=modaldel_form,
                            mainseq_upload=modalimport_form,
                            searchers=[section_tb, acccode_tb, ...])

Page Sequence

Standard Forms

Additional Document Context Keys

  • btn_set (bool): Whether the page button sets should be rendered.
  • doccount (bool): Whether the document counter elements should be rendered.
  • docverify (dict): The specifications for the document verification blocks. Each key-value pair corresponds to a single block:
    • The key is a string used for internal referencing.
    • The value is a list ([str, str, str (optional)]):
      1. A short human-readable description of the verification. This value is the popover text when the mouse cursor hovers above the block.
      2. Pill text, a highly abbreviated shorthand string that appears on the block at all time.
      3. (Optional) The name of the function to run when the verification is not an all-out pass. Usually the function serves to highlight the elements where attention is needed.
# Example from Accounting Journal (w/ Input VAT) page
doc_context = {"btn_set":   True,
               "doccount":  True,
               "docverify": {"incomp":   ["INCOMPLETE", "INCOMP", "blip_vouch_tab"],
                             "iwht":     ["INPUT WITHHOLDING TAX", "IN-WHT", "blip_wht_tab"],
                             "owht":     ["OUTPUT WITHHOLDING TAX", "WHT", "blip_wht_tab"],
                             "bvat":     ["TAX INVOICE", "VAT", "blip_vat_tab"],
                             "editting": ["EDITTING", "EDIT"]},
               **mainseq_args)
Example of a Document Page
Example of a Document Page: (1) Document Counter, (2) Document Verification, (3)~(4) Page Button Sets

More render_template Arguments

Arguments discussed under this final sub-section are not parts of the Document Context, and are to be fed directly to the render_template function. However, they are commonly utilized in tandem with Document Context, so it seems fit to list them here as well.

  • mass_populate
  • pin_args
  • back_route
  • perm_to_show

Fit the Context on an HTML Page

Page-level Permission & Document Locking

Useful Patterns