├── .gitignore ├── MANIFEST.in ├── README.md ├── docs └── screenshots │ ├── print-order.png │ ├── print-production-dialog.png │ ├── printing-workspace.png │ └── work-order-list.png ├── license.txt ├── requirements.txt ├── setup.py └── textile ├── __init__.py ├── boot.py ├── config ├── __init__.py ├── desktop.py └── docs.py ├── controllers ├── __init__.py ├── textile_order.py └── textile_pricing_rule.py ├── fabric_pretreatment ├── __init__.py ├── doctype │ ├── __init__.py │ ├── fabric_pretreatment_settings │ │ ├── __init__.py │ │ ├── fabric_pretreatment_settings.js │ │ ├── fabric_pretreatment_settings.json │ │ ├── fabric_pretreatment_settings.py │ │ └── test_fabric_pretreatment_settings.py │ ├── pretreatment_order │ │ ├── __init__.py │ │ ├── pretreatment_order.js │ │ ├── pretreatment_order.json │ │ ├── pretreatment_order.py │ │ ├── pretreatment_order_dashboard.py │ │ ├── pretreatment_order_list.js │ │ └── test_pretreatment_order.py │ ├── pretreatment_pricing_rule │ │ ├── __init__.py │ │ ├── pretreatment_pricing_rule.js │ │ ├── pretreatment_pricing_rule.json │ │ ├── pretreatment_pricing_rule.py │ │ ├── pretreatment_pricing_rule_list.js │ │ └── test_pretreatment_pricing_rule.py │ └── pretreatment_process_rule │ │ ├── __init__.py │ │ ├── pretreatment_process_rule.js │ │ ├── pretreatment_process_rule.json │ │ ├── pretreatment_process_rule.py │ │ └── test_pretreatment_process_rule.py ├── number_card │ ├── pretreatment_orders_in_production │ │ └── pretreatment_orders_in_production.json │ ├── pretreatment_orders_to_confirm │ │ └── pretreatment_orders_to_confirm.json │ ├── pretreatment_orders_to_deliver │ │ └── pretreatment_orders_to_deliver.json │ └── pretreatment_orders_to_pack │ │ └── pretreatment_orders_to_pack.json ├── report │ ├── __init__.py │ └── pretreatment_production_register │ │ ├── __init__.py │ │ ├── pretreatment_production_register.js │ │ ├── pretreatment_production_register.json │ │ └── pretreatment_production_register.py └── workspace │ └── fabric_pretreatment │ └── fabric_pretreatment.json ├── fabric_printing ├── __init__.py ├── doctype │ ├── __init__.py │ ├── coating_order │ │ ├── __init__.py │ │ ├── coating_order.js │ │ ├── coating_order.json │ │ ├── coating_order.py │ │ ├── coating_order_dashboard.py │ │ ├── coating_order_list.js │ │ └── test_coating_order.py │ ├── fabric_printer │ │ ├── __init__.py │ │ ├── fabric_printer.js │ │ ├── fabric_printer.json │ │ ├── fabric_printer.py │ │ └── test_fabric_printer.py │ ├── fabric_printing_settings │ │ ├── __init__.py │ │ ├── fabric_printing_settings.js │ │ ├── fabric_printing_settings.json │ │ ├── fabric_printing_settings.py │ │ └── test_fabric_printing_settings.py │ ├── print_order │ │ ├── __init__.py │ │ ├── print_order.js │ │ ├── print_order.json │ │ ├── print_order.py │ │ ├── print_order_dashboard.py │ │ ├── print_order_list.js │ │ └── test_print_order.py │ ├── print_order_item │ │ ├── __init__.py │ │ ├── print_order_item.json │ │ └── print_order_item.py │ ├── print_pricing_rule │ │ ├── __init__.py │ │ ├── print_pricing_rule.js │ │ ├── print_pricing_rule.json │ │ ├── print_pricing_rule.py │ │ ├── print_pricing_rule_list.js │ │ └── test_print_pricing_rule.py │ ├── print_process_rule │ │ ├── __init__.py │ │ ├── print_process_rule.js │ │ ├── print_process_rule.json │ │ ├── print_process_rule.py │ │ └── test_print_process_rule.py │ └── printed_fabric_detail │ │ ├── __init__.py │ │ ├── printed_fabric_detail.json │ │ └── printed_fabric_detail.py ├── number_card │ ├── print_orders_in_production │ │ └── print_orders_in_production.json │ ├── print_orders_to_confirm │ │ └── print_orders_to_confirm.json │ ├── print_orders_to_deliver │ │ └── print_orders_to_deliver.json │ └── print_orders_to_pack │ │ └── print_orders_to_pack.json ├── page │ ├── __init__.py │ ├── print_order_packing │ │ ├── __init__.py │ │ ├── print_order_packing.js │ │ └── print_order_packing.json │ └── print_work_order │ │ ├── __init__.py │ │ ├── print_work_order.js │ │ └── print_work_order.json ├── report │ ├── __init__.py │ ├── coating_production_register │ │ ├── __init__.py │ │ ├── coating_production_register.js │ │ ├── coating_production_register.json │ │ └── coating_production_register.py │ ├── fabric_printing_summary │ │ ├── __init__.py │ │ ├── fabric_printing_summary.js │ │ ├── fabric_printing_summary.json │ │ └── fabric_printing_summary.py │ └── print_production_register │ │ ├── __init__.py │ │ ├── print_production_register.js │ │ ├── print_production_register.json │ │ └── print_production_register.py └── workspace │ └── fabric_printing │ └── fabric_printing.json ├── fixtures ├── custom_field.json └── property_setter.json ├── hooks.py ├── install.py ├── modules.txt ├── notifications.py ├── overrides ├── bom_hooks.py ├── customer_hooks.js ├── customer_hooks.py ├── delivery_note_hooks.js ├── delivery_note_hooks.py ├── item_details_hooks.py ├── item_hooks.js ├── item_hooks.py ├── packing_slip_hooks.js ├── packing_slip_hooks.py ├── purchase_hooks.py ├── purchase_order_hooks.js ├── quotation_hooks.py ├── sales_invoice_hooks.js ├── sales_invoice_hooks.py ├── sales_order_hooks.js ├── sales_order_hooks.py ├── stock_entry_hooks.js ├── stock_entry_hooks.py ├── taxes_and_totals_hooks.js ├── taxes_and_totals_hooks.py ├── uom_hooks.py ├── work_order_hooks.js ├── work_order_hooks.py └── work_order_list_hooks.js ├── patches.txt ├── patches ├── __init__.py ├── change_panel_sales_uom_to_meter.py ├── change_print_order_status_not_started.py ├── delete_duplicate_file_attachments.py ├── delivery_status_not_applicable_for_not_started_orders.py ├── enable_allow_process_loss.py ├── fix_return_fabric_skip_sales_invoice.py ├── refactor_fabric_printing.py ├── reinstall_digital_printing.py ├── remove_item_design_name_field.py ├── rename_process_component_field.py ├── rename_stock_entry_type_for_pretreatment_production.py ├── rename_textile_item_type.py ├── set_coating_order_actual_end_date.py ├── set_default_coating_cost_center.py ├── set_default_fabric_pickup.py ├── set_do_not_explode_for_fabric.py ├── set_fabric_warehouse.py ├── set_is_sub_contracted.py ├── set_line_fabric_item_details.py ├── set_line_textile_item_type.py ├── set_panel_based_qty.py ├── set_pretreatment_greige_fabric_batch_no.py ├── set_pretreatment_order_subcontractable_qty.py ├── set_print_order_internal_customer.py ├── set_print_order_rejected_qty.py ├── set_printed_design_material_request_type.py ├── set_return_fabric_skip_sales_invoice.py ├── set_work_order_fabric_details.py ├── set_work_order_packing_slip_required.py ├── set_work_order_process_details.py ├── setup_textile_item_types.py ├── unset_sales_uom_for_printed_design_items.py ├── update_conversion_factor_global_defaults.py ├── update_fabric_conversion_uoms.py ├── update_fabric_items_conversions.py ├── update_fabric_material_tariff_numbers.py ├── update_is_return_fabric_field.py ├── update_print_order_item_creation_status.py ├── update_print_order_production_packing_status.py ├── update_print_order_statuses.py └── update_stock_entry_types.py ├── public ├── .gitkeep ├── js │ ├── check_pricing.js │ ├── print_list_view.js │ ├── textile_order.js │ └── utils.js ├── scss │ ├── print_list_view.scss │ ├── print_order_item_row.scss │ └── textile.bundle.scss └── textile.bundle.js ├── rotated_image.py ├── templates ├── __init__.py ├── pages │ └── __init__.py └── print_order_item_row.html ├── textile ├── __init__.py ├── doctype │ ├── __init__.py │ ├── fabric_material │ │ ├── __init__.py │ │ ├── fabric_material.js │ │ ├── fabric_material.json │ │ ├── fabric_material.py │ │ └── test_fabric_material.py │ ├── fabric_tariff_number │ │ ├── __init__.py │ │ ├── fabric_tariff_number.json │ │ └── fabric_tariff_number.py │ ├── fabric_type │ │ ├── __init__.py │ │ ├── fabric_type.js │ │ ├── fabric_type.json │ │ ├── fabric_type.py │ │ └── test_fabric_type.py │ ├── textile_email_digest │ │ ├── __init__.py │ │ ├── test_textile_email_digest.py │ │ ├── textile_email_digest.js │ │ ├── textile_email_digest.json │ │ └── textile_email_digest.py │ └── textile_item_type │ │ ├── __init__.py │ │ ├── test_textile_item_type.py │ │ ├── textile_item_type.js │ │ ├── textile_item_type.json │ │ └── textile_item_type.py └── report │ ├── __init__.py │ ├── fabric_delivery_register │ ├── __init__.py │ ├── fabric_delivery_register.js │ ├── fabric_delivery_register.json │ └── fabric_delivery_register.py │ ├── fabric_ledger │ ├── __init__.py │ ├── fabric_ledger.html │ ├── fabric_ledger.js │ ├── fabric_ledger.json │ └── fabric_ledger.py │ └── fabric_packing_list │ ├── __init__.py │ ├── fabric_packing_list.html │ ├── fabric_packing_list.js │ ├── fabric_packing_list.json │ └── fabric_packing_list.py ├── utils.py └── www └── __init__.py /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.pyc 3 | *.egg-info 4 | *.swp 5 | tags 6 | textile/docs/current 7 | node_modules/ 8 | __pycache__ 9 | .idea/ 10 | .vscode/ 11 | dist/ -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include MANIFEST.in 2 | include requirements.txt 3 | include *.json 4 | include *.md 5 | include *.py 6 | include *.txt 7 | recursive-include textile *.css 8 | recursive-include textile *.csv 9 | recursive-include textile *.html 10 | recursive-include textile *.ico 11 | recursive-include textile *.js 12 | recursive-include textile *.json 13 | recursive-include textile *.md 14 | recursive-include textile *.png 15 | recursive-include textile *.py 16 | recursive-include textile *.svg 17 | recursive-include textile *.txt 18 | recursive-exclude textile *.pyc -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Textile ERP App for ERPNext 2 | 3 | The Textile App is a manufacturing workspace for [ERPNext](https://github.com/frappe/erpnext) that adds workflows and customizations for the textile manufacturing process. 4 | 5 | The app workflow and design principle puts the user first, where only minimal user input is required to ensure that production process and stock levels stay in sync in real-time. The app is in active development, and not released officially yet. 6 | 7 | Note: This app only works on ParaLogic's fork of [Frappe](https://github.com/ParaLogicTech/frappe) and [ERPNext](https://github.com/ParaLogicTech/erpnext) and will not work on the official version of Frappe/ERPNext. 8 | 9 | ## Features 🎁 10 | 11 | ### 1. Digital printing on textiles 🖨️ (developed, in optimization phase) 12 | Adds a new **Print Order** DocType for roll-to-roll printing. 13 | - Create print orders for both repeats (seamless or rapport designs) and panels (with gaps between each panel). 14 | - Automatically calculate print length based on design file dimensions, gaps, and required quantity. 15 | - Automatically calculate fabric required based on above considerations and definable process wastage. 16 | - Allows for choosing primary quantity based on fabric length, design length or number of panels. 17 | - Directly see production quantity on item level: printed quantity, packed quantity and delivered quantity. 18 | - Maintains fabric traceability by batch numbers and packing labels 19 | - Generates fabric ledger for tracking every step of the production, packing and delivery process. 20 | - Accomodates for unprinted areas in printing head and tail, fabric shrinkage and scrapped fabrics. 21 | 22 | Unique BOM concept for highly accurate stock consumptions. 23 | - Flexible BOM's for reactive/disperse/pigment (based on linear-meters, area and weight), and sublimation (based on linear-meters and area). 24 | - BOM's with drop-down on Print Order level to allow recipe selections at each step, e.g. coating and finishing. 25 | - Smart BOM's for sublimation to ensure right papers are pre-selected based on fabric width. 26 | 27 | ### 2. Greige fabric pre-treatment ☀️ (developed, in optimization phase) 28 | Process steps for pre-treatment of greige fabrics: singeing, desizing, scouring, bleaching and washing. 29 | - Independent BOM's and operation tracking for each process step. 30 | - Accruate WIP stock for each process step. 31 | 32 | ## Roadmap & Wishlist ✨ 33 | - Extensive testing 34 | - Piece goods manufacturing (stitching) 👚 35 | - Drag-and-drop production re-scheduling tool 36 | - Yarn manufacturing 🧵 (planned for 2024) 37 | 38 | ## Support 🤗 39 | Please contact us for any support or other inquiries via our website https://paralogic.io. 40 | 41 | ## Contributing 🤝 42 | You can fork this repository and create a pull request to contribute code. By contributing to Textile App for ERPNext, you agree that your contributions will be licensed under its GNU General Public License (v3). 43 | 44 | ## GNU/General Public License 45 | The ERPNext Pakistan Workspace code is licensed as GNU General Public License (v3) and the copyright is owned by ParaLogic and Contributors (see [license.txt](license.txt)). 46 | 47 | ## Screenshots 48 | 49 | ### Dashboard / Workspace 50 | 51 | Printing Workspace 52 | 53 | ### Print Order 54 | Print Order 55 | 56 | ### Work Order List 57 | Work Order List 58 | 59 | ### Simplified Production Entry 60 | Print Production Dialog 61 | -------------------------------------------------------------------------------- /docs/screenshots/print-order.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/docs/screenshots/print-order.png -------------------------------------------------------------------------------- /docs/screenshots/print-production-dialog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/docs/screenshots/print-production-dialog.png -------------------------------------------------------------------------------- /docs/screenshots/printing-workspace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/docs/screenshots/printing-workspace.png -------------------------------------------------------------------------------- /docs/screenshots/work-order-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/docs/screenshots/work-order-list.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # frappe -- https://github.com/frappe/frappe is installed via 'bench init' -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | with open("requirements.txt") as f: 4 | install_requires = f.read().strip().split("\n") 5 | 6 | # get version from __version__ variable in textile/__init__.py 7 | from textile import __version__ as version 8 | 9 | setup( 10 | name="textile", 11 | version=version, 12 | description="Textile ERP Application", 13 | author="ParaLogic", 14 | author_email="info@paralogic.io", 15 | packages=find_packages(), 16 | zip_safe=False, 17 | include_package_data=True, 18 | install_requires=install_requires 19 | ) 20 | -------------------------------------------------------------------------------- /textile/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | __version__ = '0.0.1' 3 | 4 | -------------------------------------------------------------------------------- /textile/boot.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | from frappe import _ 3 | 4 | 5 | def boot_session(bootinfo): 6 | if frappe.session['user'] != 'Guest': 7 | if not bootinfo.get('additional_sle_filters'): 8 | bootinfo.additional_sle_filters = [] 9 | 10 | bootinfo.additional_sle_filters.append({ 11 | 'label': _("Fabric Item"), 12 | 'fieldname': 'fabric_item', 13 | 'fieldtype': 'Link', 14 | 'options': 'Item', 15 | 'get_query': { 16 | 'filters': { 17 | 'textile_item_type': ['in', ['Greige Fabric', 'Ready Fabric']] 18 | } 19 | } 20 | }) 21 | 22 | 23 | def set_sle_item_conditions(filters, conditions, alias="`tabItem`"): 24 | from textile.utils import get_combined_fabric_items 25 | 26 | fabric_item = filters.get('fabric_item') 27 | if fabric_item: 28 | combined = get_combined_fabric_items(fabric_item) 29 | if combined.textile_item_type not in ("Ready Fabric", "Greige Fabric"): 30 | frappe.throw(_("Fabric Item filter must be either Ready Fabric or Greige Fabric")) 31 | 32 | if combined.fabric_item_codes: 33 | filters["fabric_item_codes"] = combined.fabric_item_codes 34 | conditions.append(f"{alias}.name in %(fabric_item_codes)s") 35 | else: 36 | conditions.append(f"{alias}.name = %(fabric_item)s") 37 | -------------------------------------------------------------------------------- /textile/config/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/config/__init__.py -------------------------------------------------------------------------------- /textile/config/desktop.py: -------------------------------------------------------------------------------- 1 | from frappe import _ 2 | 3 | def get_data(): 4 | return [ 5 | { 6 | "module_name": "Textile", 7 | "type": "module", 8 | "label": _("Textile") 9 | }, 10 | { 11 | "module_name": "Fabric Printing", 12 | "type": "module", 13 | "label": _("Fabric Printing") 14 | }, 15 | ] 16 | -------------------------------------------------------------------------------- /textile/config/docs.py: -------------------------------------------------------------------------------- 1 | """ 2 | Configuration for docs 3 | """ 4 | 5 | # source_link = "https://github.com/[org_name]/textile" 6 | # headline = "App that does everything" 7 | # sub_heading = "Yes, you got that right the first time, everything" 8 | 9 | def get_context(context): 10 | context.brand_html = "Textile" 11 | -------------------------------------------------------------------------------- /textile/controllers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/controllers/__init__.py -------------------------------------------------------------------------------- /textile/fabric_pretreatment/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/fabric_pretreatment/__init__.py -------------------------------------------------------------------------------- /textile/fabric_pretreatment/doctype/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/fabric_pretreatment/doctype/__init__.py -------------------------------------------------------------------------------- /textile/fabric_pretreatment/doctype/fabric_pretreatment_settings/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/fabric_pretreatment/doctype/fabric_pretreatment_settings/__init__.py -------------------------------------------------------------------------------- /textile/fabric_pretreatment/doctype/fabric_pretreatment_settings/fabric_pretreatment_settings.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, ParaLogic and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('Fabric Pretreatment Settings', { 5 | onload: function(frm) { 6 | erpnext.queries.setup_queries(frm, "Warehouse", function(fieldname) { 7 | return erpnext.queries.warehouse(frm.doc); 8 | }); 9 | 10 | frm.set_query("default_pretreatment_cost_center", function(doc) { 11 | return { 12 | filters: { 13 | "is_group": 0 14 | } 15 | }; 16 | }); 17 | 18 | frm.set_query("stock_entry_type_for_fabric_transfer", function(doc) { 19 | return { 20 | filters: { 21 | purpose: "Material Transfer for Manufacture", 22 | } 23 | }; 24 | }); 25 | frm.set_query("stock_entry_type_for_pretreatment_production", function(doc) { 26 | return { 27 | filters: { 28 | purpose: "Manufacture", 29 | } 30 | }; 31 | }); 32 | frm.set_query("stock_entry_type_for_operation_consumption", function(doc) { 33 | return { 34 | filters: { 35 | purpose: "Material Consumption for Manufacture", 36 | } 37 | }; 38 | }); 39 | frm.set_query("stock_entry_type_for_fabric_rejection", function(doc) { 40 | return { 41 | filters: { 42 | purpose: "Material Transfer", 43 | } 44 | }; 45 | }); 46 | } 47 | }); 48 | -------------------------------------------------------------------------------- /textile/fabric_pretreatment/doctype/fabric_pretreatment_settings/fabric_pretreatment_settings.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, ParaLogic and contributors 2 | # For license information, please see license.txt 3 | 4 | import frappe 5 | from frappe.model.document import Document 6 | 7 | 8 | class FabricPretreatmentSettings(Document): 9 | def validate(self): 10 | self.update_global_defaults() 11 | 12 | def update_global_defaults(self): 13 | global_default_fields = [ 14 | "default_pretreatment_fabric_warehouse", 15 | "default_pretreatment_source_warehouse", 16 | "default_pretreatment_wip_warehouse", 17 | "default_pretreatment_fg_warehouse", 18 | "default_pretreatment_cost_center", 19 | ] 20 | 21 | for fn in global_default_fields: 22 | frappe.db.set_default(fn, self.get(fn, '')) 23 | -------------------------------------------------------------------------------- /textile/fabric_pretreatment/doctype/fabric_pretreatment_settings/test_fabric_pretreatment_settings.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, ParaLogic and Contributors 2 | # See license.txt 3 | 4 | # import frappe 5 | from frappe.tests.utils import FrappeTestCase 6 | 7 | 8 | class TestFabricPretreatmentSettings(FrappeTestCase): 9 | pass 10 | -------------------------------------------------------------------------------- /textile/fabric_pretreatment/doctype/pretreatment_order/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/fabric_pretreatment/doctype/pretreatment_order/__init__.py -------------------------------------------------------------------------------- /textile/fabric_pretreatment/doctype/pretreatment_order/pretreatment_order_dashboard.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | from frappe import _ 3 | 4 | 5 | def get_data(): 6 | return { 7 | 'fieldname': 'pretreatment_order', 8 | 'transactions': [ 9 | { 10 | 'label': _("Order & Billing"), 11 | 'items': ['Sales Order', 'Sales Invoice'] 12 | }, 13 | { 14 | 'label': _("Production"), 15 | 'items': ['Work Order', 'Job Card', 'Stock Entry'] 16 | }, 17 | { 18 | 'label': _("Delivery"), 19 | 'items': ['Packing Slip', 'Delivery Note'] 20 | }, 21 | { 22 | 'label': _("Subcontracting"), 23 | 'items': ['Purchase Order', 'Purchase Receipt'] 24 | }, 25 | { 26 | 'label': _("Printing"), 27 | 'items': ['Print Order'] 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /textile/fabric_pretreatment/doctype/pretreatment_order/pretreatment_order_list.js: -------------------------------------------------------------------------------- 1 | frappe.listview_settings['Pretreatment Order'] = { 2 | add_fields: ["status"], 3 | 4 | get_indicator: function(doc) { 5 | if (doc.status === "Not Started") { 6 | return [__(doc.status), "yellow", "status,=," + doc.status]; 7 | } else if(doc.status === "To Produce") { 8 | return [__(doc.status), "purple", "status,=," + doc.status]; 9 | } else if(doc.status === "To Deliver") { 10 | return [__(doc.status), "orange", "status,=," + doc.status]; 11 | } else if(doc.status === "To Bill") { 12 | return [__(doc.status), "yellow", "status,=," + doc.status]; 13 | } else if(["Completed", "Closed"].includes(doc.status)) { 14 | return [__(doc.status), "green", "status,=," + doc.status]; 15 | } 16 | }, 17 | 18 | onload: function(listview) { 19 | if (listview.page.fields_dict.greige_fabric_item) { 20 | listview.page.fields_dict.greige_fabric_item.get_query = () => { 21 | return erpnext.queries.item({"textile_item_type": "Greige Fabric", "include_disabled": 1}); 22 | } 23 | } 24 | if (listview.page.fields_dict.ready_fabric_item) { 25 | listview.page.fields_dict.ready_fabric_item.get_query = () => { 26 | return erpnext.queries.item({"textile_item_type": "Ready Fabric", "include_disabled": 1}); 27 | } 28 | } 29 | }, 30 | }; 31 | -------------------------------------------------------------------------------- /textile/fabric_pretreatment/doctype/pretreatment_order/test_pretreatment_order.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, ParaLogic and Contributors 2 | # See license.txt 3 | 4 | # import frappe 5 | from frappe.tests.utils import FrappeTestCase 6 | 7 | 8 | class TestPretreatmentOrder(FrappeTestCase): 9 | pass 10 | -------------------------------------------------------------------------------- /textile/fabric_pretreatment/doctype/pretreatment_pricing_rule/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/fabric_pretreatment/doctype/pretreatment_pricing_rule/__init__.py -------------------------------------------------------------------------------- /textile/fabric_pretreatment/doctype/pretreatment_pricing_rule/pretreatment_pricing_rule.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024, ParaLogic and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('Pretreatment Pricing Rule', { 5 | setup: function(frm) { 6 | frm.set_query("price_list", () => { 7 | return { 8 | filters: { 9 | selling: 1 10 | } 11 | } 12 | }) 13 | } 14 | }); 15 | -------------------------------------------------------------------------------- /textile/fabric_pretreatment/doctype/pretreatment_pricing_rule/pretreatment_pricing_rule.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "allow_rename": 1, 4 | "autoname": "field:pretreatment_pricing_rule_name", 5 | "creation": "2024-02-08 13:10:13.620834", 6 | "default_view": "List", 7 | "doctype": "DocType", 8 | "editable_grid": 1, 9 | "engine": "InnoDB", 10 | "field_order": [ 11 | "pretreatment_pricing_rule_name", 12 | "filter_criteria_section", 13 | "price_list", 14 | "customer_group", 15 | "column_break_jdhll", 16 | "fabric_material", 17 | "fabric_type", 18 | "column_break_qefhw", 19 | "fabric_width_lower_limit", 20 | "fabric_width_upper_limit", 21 | "column_break_auf3m", 22 | "fabric_gsm_lower_limit", 23 | "fabric_gsm_upper_limit", 24 | "pricing_section", 25 | "type", 26 | "column_break_jq8di", 27 | "value" 28 | ], 29 | "fields": [ 30 | { 31 | "fieldname": "pretreatment_pricing_rule_name", 32 | "fieldtype": "Data", 33 | "label": "Pretreatment Pricing Rule Name", 34 | "reqd": 1, 35 | "unique": 1 36 | }, 37 | { 38 | "fieldname": "filter_criteria_section", 39 | "fieldtype": "Section Break", 40 | "label": "Filter Criteria" 41 | }, 42 | { 43 | "fieldname": "price_list", 44 | "fieldtype": "Link", 45 | "in_list_view": 1, 46 | "in_standard_filter": 1, 47 | "label": "Price List", 48 | "options": "Price List", 49 | "reqd": 1 50 | }, 51 | { 52 | "fieldname": "customer_group", 53 | "fieldtype": "Link", 54 | "in_standard_filter": 1, 55 | "label": "Customer Group", 56 | "options": "Customer Group" 57 | }, 58 | { 59 | "fieldname": "column_break_jdhll", 60 | "fieldtype": "Column Break" 61 | }, 62 | { 63 | "fieldname": "fabric_material", 64 | "fieldtype": "Link", 65 | "in_standard_filter": 1, 66 | "label": "Fabric Material", 67 | "options": "Fabric Material" 68 | }, 69 | { 70 | "fieldname": "fabric_type", 71 | "fieldtype": "Link", 72 | "in_standard_filter": 1, 73 | "label": "Fabric Type", 74 | "options": "Fabric Type" 75 | }, 76 | { 77 | "fieldname": "column_break_qefhw", 78 | "fieldtype": "Column Break" 79 | }, 80 | { 81 | "fieldname": "fabric_width_lower_limit", 82 | "fieldtype": "Float", 83 | "label": "Fabric Width Lower Limit", 84 | "non_negative": 1, 85 | "precision": "1" 86 | }, 87 | { 88 | "fieldname": "fabric_width_upper_limit", 89 | "fieldtype": "Float", 90 | "label": "Fabric Width Upper Limit", 91 | "non_negative": 1, 92 | "precision": "1" 93 | }, 94 | { 95 | "fieldname": "column_break_auf3m", 96 | "fieldtype": "Column Break" 97 | }, 98 | { 99 | "fieldname": "fabric_gsm_lower_limit", 100 | "fieldtype": "Float", 101 | "label": "Fabric GSM Lower Limit", 102 | "non_negative": 1, 103 | "precision": "1" 104 | }, 105 | { 106 | "fieldname": "fabric_gsm_upper_limit", 107 | "fieldtype": "Float", 108 | "label": "Fabric GSM Upper Limit", 109 | "non_negative": 1, 110 | "precision": "1" 111 | }, 112 | { 113 | "fieldname": "pricing_section", 114 | "fieldtype": "Section Break", 115 | "label": "Pricing" 116 | }, 117 | { 118 | "fieldname": "type", 119 | "fieldtype": "Select", 120 | "in_list_view": 1, 121 | "in_standard_filter": 1, 122 | "label": "Type", 123 | "options": "\nBase Rate\nAdd/Subtract\nMultiply", 124 | "reqd": 1 125 | }, 126 | { 127 | "fieldname": "column_break_jq8di", 128 | "fieldtype": "Column Break" 129 | }, 130 | { 131 | "fieldname": "value", 132 | "fieldtype": "Float", 133 | "in_list_view": 1, 134 | "label": "Value", 135 | "reqd": 1 136 | } 137 | ], 138 | "index_web_pages_for_search": 1, 139 | "links": [], 140 | "modified": "2024-03-19 18:29:32.135365", 141 | "modified_by": "Administrator", 142 | "module": "Fabric Pretreatment", 143 | "name": "Pretreatment Pricing Rule", 144 | "naming_rule": "By fieldname", 145 | "owner": "Administrator", 146 | "permissions": [ 147 | { 148 | "create": 1, 149 | "delete": 1, 150 | "email": 1, 151 | "export": 1, 152 | "print": 1, 153 | "read": 1, 154 | "report": 1, 155 | "role": "System Manager", 156 | "share": 1, 157 | "write": 1 158 | }, 159 | { 160 | "email": 1, 161 | "export": 1, 162 | "print": 1, 163 | "read": 1, 164 | "report": 1, 165 | "role": "Invoice User", 166 | "share": 1 167 | }, 168 | { 169 | "email": 1, 170 | "export": 1, 171 | "print": 1, 172 | "read": 1, 173 | "report": 1, 174 | "role": "Accounts User", 175 | "share": 1 176 | } 177 | ], 178 | "sort_field": "modified", 179 | "sort_order": "DESC", 180 | "states": [], 181 | "track_changes": 1 182 | } -------------------------------------------------------------------------------- /textile/fabric_pretreatment/doctype/pretreatment_pricing_rule/pretreatment_pricing_rule.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, ParaLogic and contributors 2 | # For license information, please see license.txt 3 | 4 | import frappe 5 | from frappe.utils import flt 6 | from textile.controllers.textile_pricing_rule import TextilePricingRule 7 | from erpnext.stock.doctype.item.item import convert_item_uom_for 8 | 9 | 10 | class PretreatmentPricingRule(TextilePricingRule): 11 | doctype = "Pretreatment Pricing Rule" 12 | cache_field = "pretreatment_pricing_rule_names" 13 | 14 | @classmethod 15 | def get_customer_base_rate(cls, customer): 16 | return flt(frappe.get_cached_value("Customer", customer, "base_pretreatment_rate")) 17 | 18 | @classmethod 19 | def is_fixed_base_rate(cls, customer): 20 | return frappe.get_cached_value("Customer", customer, "is_fixed_pretreatment_rate") 21 | 22 | 23 | @frappe.whitelist() 24 | def get_pretreatment_rate(design_item, price_list, customer=None, uom=None, conversion_factor=None): 25 | pretreatment_rate = PretreatmentPricingRule.get_applied_rule(design_item, price_list, customer)["rule_rate"] 26 | 27 | item = frappe.get_cached_doc("Item", design_item) 28 | if uom and uom != item.stock_uom: 29 | pretreatment_rate = convert_item_uom_for( 30 | value=pretreatment_rate, 31 | item_code=item.name, 32 | from_uom=item.stock_uom, 33 | to_uom=uom, 34 | conversion_factor=conversion_factor, 35 | is_rate=True 36 | ) 37 | 38 | return pretreatment_rate 39 | 40 | 41 | @frappe.whitelist() 42 | def get_pretreatment_rate_breakup(item_code, price_list, customer=None): 43 | from textile.controllers.textile_pricing_rule import get_fabric_rate 44 | 45 | out = PretreatmentPricingRule.get_applied_rule(item_code, price_list, customer) 46 | fabric_rate = get_fabric_rate(item_code, price_list, frappe._dict({"customer": customer})) 47 | 48 | out.fabric_rate = fabric_rate 49 | out.price_list_rate = fabric_rate + flt(out.get("rule_rate")) 50 | 51 | out["applied_rules"] = [] 52 | for d in [out.base_rate_rule] + out.addition_rules + out.multiplier_rules: 53 | if not d: 54 | continue 55 | 56 | out.applied_rules.append({ 57 | "rule": d.name, 58 | "customer": d.customer, 59 | "type": d.type, 60 | "value": d.value, 61 | }) 62 | 63 | return out 64 | -------------------------------------------------------------------------------- /textile/fabric_pretreatment/doctype/pretreatment_pricing_rule/pretreatment_pricing_rule_list.js: -------------------------------------------------------------------------------- 1 | frappe.listview_settings["Pretreatment Pricing Rule"] = { 2 | onload: function(listview) { 3 | listview.page.add_menu_item(__("Check Pretreatment Rate"), () => { 4 | textile.show_pretreatment_pricing_dialog(); 5 | }); 6 | } 7 | }; 8 | -------------------------------------------------------------------------------- /textile/fabric_pretreatment/doctype/pretreatment_pricing_rule/test_pretreatment_pricing_rule.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2024, ParaLogic and Contributors 2 | # See license.txt 3 | 4 | # import frappe 5 | from frappe.tests.utils import FrappeTestCase 6 | 7 | 8 | class TestPretreatmentPricingRule(FrappeTestCase): 9 | pass 10 | -------------------------------------------------------------------------------- /textile/fabric_pretreatment/doctype/pretreatment_process_rule/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/fabric_pretreatment/doctype/pretreatment_process_rule/__init__.py -------------------------------------------------------------------------------- /textile/fabric_pretreatment/doctype/pretreatment_process_rule/pretreatment_process_rule.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, ParaLogic and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.provide("textile"); 5 | 6 | textile.PretreatmentProcessRule = class PretreatmentProcessRule extends frappe.ui.form.Controller { 7 | setup() { 8 | this.setup_queries(); 9 | } 10 | 11 | setup_queries() { 12 | for (let [component_item_field, component_type] of Object.entries(textile.pretreatment_components)) { 13 | this.frm.set_query(component_item_field, () => { 14 | return erpnext.queries.item({ 15 | textile_item_type: 'Process Component', 16 | process_component: component_type 17 | }); 18 | }); 19 | } 20 | } 21 | } 22 | 23 | extend_cscript(cur_frm.cscript, new textile.PretreatmentProcessRule({frm: cur_frm})); 24 | -------------------------------------------------------------------------------- /textile/fabric_pretreatment/doctype/pretreatment_process_rule/pretreatment_process_rule.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "allow_rename": 1, 4 | "autoname": "field:pretreatment_process_rule_name", 5 | "creation": "2023-09-12 23:17:46.193131", 6 | "default_view": "List", 7 | "doctype": "DocType", 8 | "editable_grid": 1, 9 | "engine": "InnoDB", 10 | "field_order": [ 11 | "pretreatment_process_rule_name", 12 | "filter_criteria_section", 13 | "fabric_material", 14 | "column_break_fze2w", 15 | "fabric_type", 16 | "process_details_section", 17 | "singeing_item", 18 | "singeing_item_name", 19 | "column_break_sioio", 20 | "desizing_item", 21 | "desizing_item_name", 22 | "desizing_item_unset", 23 | "column_break_8qvrk", 24 | "bleaching_item", 25 | "bleaching_item_name" 26 | ], 27 | "fields": [ 28 | { 29 | "fieldname": "pretreatment_process_rule_name", 30 | "fieldtype": "Data", 31 | "label": "Pretreatment Process Rule Name", 32 | "reqd": 1, 33 | "unique": 1 34 | }, 35 | { 36 | "fieldname": "filter_criteria_section", 37 | "fieldtype": "Section Break", 38 | "label": "Filter Criteria" 39 | }, 40 | { 41 | "fieldname": "fabric_material", 42 | "fieldtype": "Link", 43 | "in_list_view": 1, 44 | "in_standard_filter": 1, 45 | "label": "Fabric Material", 46 | "options": "Fabric Material" 47 | }, 48 | { 49 | "fieldname": "column_break_fze2w", 50 | "fieldtype": "Column Break" 51 | }, 52 | { 53 | "fieldname": "fabric_type", 54 | "fieldtype": "Link", 55 | "in_list_view": 1, 56 | "in_standard_filter": 1, 57 | "label": "Fabric Type", 58 | "options": "Fabric Type" 59 | }, 60 | { 61 | "fieldname": "process_details_section", 62 | "fieldtype": "Section Break", 63 | "label": "Process Details" 64 | }, 65 | { 66 | "fieldname": "singeing_item", 67 | "fieldtype": "Link", 68 | "in_list_view": 1, 69 | "in_standard_filter": 1, 70 | "label": "Singeing Item", 71 | "options": "Item" 72 | }, 73 | { 74 | "depends_on": "eval:doc.singeing_item && doc.singeing_item_name != doc.singeing_item", 75 | "fetch_from": "singeing_item.item_name", 76 | "fieldname": "singeing_item_name", 77 | "fieldtype": "Data", 78 | "label": "Singeing Item Name", 79 | "read_only": 1 80 | }, 81 | { 82 | "fieldname": "column_break_sioio", 83 | "fieldtype": "Column Break" 84 | }, 85 | { 86 | "depends_on": "eval:!doc.desizing_item_unset", 87 | "fieldname": "desizing_item", 88 | "fieldtype": "Link", 89 | "in_list_view": 1, 90 | "in_standard_filter": 1, 91 | "label": "Desizing Item", 92 | "options": "Item" 93 | }, 94 | { 95 | "depends_on": "eval:!doc.desizing_item_unset && doc.desizing_item && doc.desizing_item_name != doc.desizing_item", 96 | "fetch_from": "desizing_item.item_name", 97 | "fieldname": "desizing_item_name", 98 | "fieldtype": "Data", 99 | "label": "Desizing Item Name", 100 | "read_only": 1 101 | }, 102 | { 103 | "fieldname": "column_break_8qvrk", 104 | "fieldtype": "Column Break" 105 | }, 106 | { 107 | "fieldname": "bleaching_item", 108 | "fieldtype": "Link", 109 | "in_list_view": 1, 110 | "in_standard_filter": 1, 111 | "label": "Bleaching Item", 112 | "options": "Item" 113 | }, 114 | { 115 | "depends_on": "eval:doc.bleaching_item && doc.bleaching_item_name != doc.bleaching_item", 116 | "fetch_from": "bleaching_item.item_name", 117 | "fieldname": "bleaching_item_name", 118 | "fieldtype": "Data", 119 | "label": "Bleaching Item Name", 120 | "read_only": 1 121 | }, 122 | { 123 | "default": "0", 124 | "fieldname": "desizing_item_unset", 125 | "fieldtype": "Check", 126 | "label": "Desizing Not Required" 127 | } 128 | ], 129 | "index_web_pages_for_search": 1, 130 | "links": [], 131 | "modified": "2024-03-18 10:38:56.756166", 132 | "modified_by": "Administrator", 133 | "module": "Fabric Pretreatment", 134 | "name": "Pretreatment Process Rule", 135 | "naming_rule": "By fieldname", 136 | "owner": "Administrator", 137 | "permissions": [ 138 | { 139 | "create": 1, 140 | "delete": 1, 141 | "email": 1, 142 | "export": 1, 143 | "print": 1, 144 | "read": 1, 145 | "report": 1, 146 | "role": "System Manager", 147 | "share": 1, 148 | "write": 1 149 | }, 150 | { 151 | "email": 1, 152 | "export": 1, 153 | "print": 1, 154 | "read": 1, 155 | "report": 1, 156 | "role": "Pretreatment Sales User", 157 | "share": 1 158 | } 159 | ], 160 | "sort_field": "modified", 161 | "sort_order": "DESC", 162 | "states": [], 163 | "track_changes": 1 164 | } -------------------------------------------------------------------------------- /textile/fabric_pretreatment/doctype/pretreatment_process_rule/test_pretreatment_process_rule.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, ParaLogic and Contributors 2 | # See license.txt 3 | 4 | # import frappe 5 | from frappe.tests.utils import FrappeTestCase 6 | 7 | 8 | class TestPretreatmentProcessRule(FrappeTestCase): 9 | pass 10 | -------------------------------------------------------------------------------- /textile/fabric_pretreatment/number_card/pretreatment_orders_in_production/pretreatment_orders_in_production.json: -------------------------------------------------------------------------------- 1 | { 2 | "aggregate_function_based_on": "", 3 | "color": "#761ACB", 4 | "creation": "2023-09-12 22:58:49.267847", 5 | "docstatus": 0, 6 | "doctype": "Number Card", 7 | "document_type": "Pretreatment Order", 8 | "dynamic_filters_json": "[]", 9 | "filters_json": "[[\"Pretreatment Order\",\"docstatus\",\"=\",\"1\",false],[\"Pretreatment Order\",\"status\",\"=\",\"To Produce\",false],[\"Pretreatment Order\",\"status\",\"!=\",\"Closed\",false]]", 10 | "function": "Count", 11 | "idx": 0, 12 | "is_public": 1, 13 | "is_standard": 1, 14 | "label": "Pretreatment Orders In Production", 15 | "modified": "2023-09-13 15:00:45.089826", 16 | "modified_by": "Administrator", 17 | "module": "Fabric Pretreatment", 18 | "name": "Pretreatment Orders In Production", 19 | "owner": "Administrator", 20 | "parent_document_type": "", 21 | "report_function": "Sum", 22 | "show_percentage_stats": 0, 23 | "stats_time_interval": "Daily", 24 | "type": "Document Type" 25 | } -------------------------------------------------------------------------------- /textile/fabric_pretreatment/number_card/pretreatment_orders_to_confirm/pretreatment_orders_to_confirm.json: -------------------------------------------------------------------------------- 1 | { 2 | "aggregate_function_based_on": "", 3 | "color": "#ECAD4B", 4 | "creation": "2023-09-12 22:57:20.514842", 5 | "docstatus": 0, 6 | "doctype": "Number Card", 7 | "document_type": "Pretreatment Order", 8 | "dynamic_filters_json": "[]", 9 | "filters_json": "[[\"Pretreatment Order\",\"status\",\"in\",[\"Draft\",\"Not Started\"],false]]", 10 | "function": "Count", 11 | "idx": 0, 12 | "is_public": 1, 13 | "is_standard": 1, 14 | "label": "Pretreatment Orders To Confirm", 15 | "modified": "2024-07-06 14:41:27.618384", 16 | "modified_by": "Administrator", 17 | "module": "Fabric Pretreatment", 18 | "name": "Pretreatment Orders To Confirm", 19 | "owner": "Administrator", 20 | "parent_document_type": "", 21 | "report_function": "Sum", 22 | "show_percentage_stats": 1, 23 | "stats_time_interval": "Daily", 24 | "type": "Document Type" 25 | } -------------------------------------------------------------------------------- /textile/fabric_pretreatment/number_card/pretreatment_orders_to_deliver/pretreatment_orders_to_deliver.json: -------------------------------------------------------------------------------- 1 | { 2 | "aggregate_function_based_on": "", 3 | "color": "#EC864B", 4 | "creation": "2023-09-12 23:00:39.237982", 5 | "docstatus": 0, 6 | "doctype": "Number Card", 7 | "document_type": "Pretreatment Order", 8 | "dynamic_filters_json": "[]", 9 | "filters_json": "[[\"Pretreatment Order\",\"docstatus\",\"=\",\"1\",false],[\"Pretreatment Order\",\"status\",\"=\",\"To Deliver\",false]]", 10 | "function": "Count", 11 | "idx": 0, 12 | "is_public": 1, 13 | "is_standard": 1, 14 | "label": "Pretreatment Orders To Deliver", 15 | "modified": "2023-09-12 23:02:10.991247", 16 | "modified_by": "Administrator", 17 | "module": "Fabric Pretreatment", 18 | "name": "Pretreatment Orders To Deliver", 19 | "owner": "Administrator", 20 | "parent_document_type": "", 21 | "report_function": "Sum", 22 | "show_percentage_stats": 0, 23 | "stats_time_interval": "Daily", 24 | "type": "Document Type" 25 | } -------------------------------------------------------------------------------- /textile/fabric_pretreatment/number_card/pretreatment_orders_to_pack/pretreatment_orders_to_pack.json: -------------------------------------------------------------------------------- 1 | { 2 | "aggregate_function_based_on": "", 3 | "color": "#4463F0", 4 | "creation": "2023-09-12 22:59:59.288715", 5 | "docstatus": 0, 6 | "doctype": "Number Card", 7 | "document_type": "Pretreatment Order", 8 | "dynamic_filters_json": "[]", 9 | "filters_json": "[[\"Pretreatment Order\",\"docstatus\",\"=\",\"1\",false],[\"Pretreatment Order\",\"packing_status\",\"=\",\"To Pack\",false]]", 10 | "function": "Count", 11 | "idx": 0, 12 | "is_public": 1, 13 | "is_standard": 1, 14 | "label": "Pretreatment Orders To Pack", 15 | "modified": "2023-09-12 23:02:08.382719", 16 | "modified_by": "Administrator", 17 | "module": "Fabric Pretreatment", 18 | "name": "Pretreatment Orders To Pack", 19 | "owner": "Administrator", 20 | "parent_document_type": "", 21 | "report_function": "Sum", 22 | "show_percentage_stats": 0, 23 | "stats_time_interval": "Daily", 24 | "type": "Document Type" 25 | } -------------------------------------------------------------------------------- /textile/fabric_pretreatment/report/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/fabric_pretreatment/report/__init__.py -------------------------------------------------------------------------------- /textile/fabric_pretreatment/report/pretreatment_production_register/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/fabric_pretreatment/report/pretreatment_production_register/__init__.py -------------------------------------------------------------------------------- /textile/fabric_pretreatment/report/pretreatment_production_register/pretreatment_production_register.json: -------------------------------------------------------------------------------- 1 | { 2 | "add_total_row": 1, 3 | "columns": [], 4 | "creation": "2023-11-15 17:15:34.173451", 5 | "disable_prepared_report": 0, 6 | "disabled": 0, 7 | "docstatus": 0, 8 | "doctype": "Report", 9 | "filters": [], 10 | "idx": 0, 11 | "is_standard": "Yes", 12 | "modified": "2024-03-18 15:12:21.609936", 13 | "modified_by": "Administrator", 14 | "module": "Fabric Pretreatment", 15 | "name": "Pretreatment Production Register", 16 | "owner": "Administrator", 17 | "prepared_report": 0, 18 | "ref_doctype": "Pretreatment Order", 19 | "report_name": "Pretreatment Production Register", 20 | "report_type": "Script Report", 21 | "roles": [ 22 | { 23 | "role": "Accounts User" 24 | }, 25 | { 26 | "role": "Pretreatment Sales User" 27 | } 28 | ] 29 | } -------------------------------------------------------------------------------- /textile/fabric_printing/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/fabric_printing/__init__.py -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/fabric_printing/doctype/__init__.py -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/coating_order/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/fabric_printing/doctype/coating_order/__init__.py -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/coating_order/coating_order_dashboard.py: -------------------------------------------------------------------------------- 1 | from frappe import _ 2 | 3 | def get_data(): 4 | return { 5 | 'fieldname': 'coating_order', 6 | 'transactions': [ 7 | { 8 | 'label': _('Production'), 9 | 'items': ['Stock Entry'] 10 | }, 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/coating_order/coating_order_list.js: -------------------------------------------------------------------------------- 1 | frappe.listview_settings['Coating Order'] = { 2 | add_fields: ["status"], 3 | 4 | get_indicator: function(doc) { 5 | return [__(doc.status), { 6 | "Not Started": "yellow", 7 | "In Process": "orange", 8 | "Stopped": "green", 9 | "Completed": "green", 10 | }[doc.status], "status,=," + doc.status]; 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/coating_order/test_coating_order.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, ParaLogic and Contributors 2 | # See license.txt 3 | 4 | # import frappe 5 | from frappe.tests.utils import FrappeTestCase 6 | 7 | 8 | class TestCoatingOrder(FrappeTestCase): 9 | pass 10 | -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/fabric_printer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/fabric_printing/doctype/fabric_printer/__init__.py -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/fabric_printer/fabric_printer.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, ParaLogic and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('Fabric Printer', { 5 | setup: function(frm) { 6 | frm.set_query("process_item", () => { 7 | return erpnext.queries.item({ textile_item_type: 'Print Process' }); 8 | }); 9 | } 10 | }); 11 | -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/fabric_printer/fabric_printer.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "allow_rename": 1, 4 | "autoname": "field:printer_name", 5 | "creation": "2023-06-21 16:12:07.100308", 6 | "default_view": "List", 7 | "doctype": "DocType", 8 | "editable_grid": 1, 9 | "engine": "InnoDB", 10 | "field_order": [ 11 | "printer_name", 12 | "process_item", 13 | "process_item_name" 14 | ], 15 | "fields": [ 16 | { 17 | "allow_in_quick_entry": 1, 18 | "fieldname": "printer_name", 19 | "fieldtype": "Data", 20 | "in_list_view": 1, 21 | "label": "Printer Name", 22 | "reqd": 1, 23 | "unique": 1 24 | }, 25 | { 26 | "allow_in_quick_entry": 1, 27 | "fieldname": "process_item", 28 | "fieldtype": "Link", 29 | "in_list_view": 1, 30 | "label": "Process Item", 31 | "options": "Item", 32 | "reqd": 1 33 | }, 34 | { 35 | "allow_in_quick_entry": 1, 36 | "fetch_from": "process_item.item_name", 37 | "fieldname": "process_item_name", 38 | "fieldtype": "Data", 39 | "label": "Process Item Name", 40 | "read_only": 1 41 | } 42 | ], 43 | "index_web_pages_for_search": 1, 44 | "links": [], 45 | "modified": "2024-03-19 18:24:04.482682", 46 | "modified_by": "Administrator", 47 | "module": "Fabric Printing", 48 | "name": "Fabric Printer", 49 | "naming_rule": "By fieldname", 50 | "owner": "Administrator", 51 | "permissions": [ 52 | { 53 | "create": 1, 54 | "delete": 1, 55 | "email": 1, 56 | "export": 1, 57 | "print": 1, 58 | "read": 1, 59 | "report": 1, 60 | "role": "System Manager", 61 | "share": 1, 62 | "write": 1 63 | }, 64 | { 65 | "email": 1, 66 | "export": 1, 67 | "print": 1, 68 | "read": 1, 69 | "report": 1, 70 | "role": "Print Production User", 71 | "share": 1 72 | }, 73 | { 74 | "email": 1, 75 | "export": 1, 76 | "print": 1, 77 | "read": 1, 78 | "report": 1, 79 | "role": "Print Sales User", 80 | "share": 1 81 | } 82 | ], 83 | "search_fields": "process_item_name", 84 | "sort_field": "idx", 85 | "sort_order": "DESC", 86 | "states": [], 87 | "track_changes": 1 88 | } -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/fabric_printer/fabric_printer.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, ParaLogic and contributors 2 | # For license information, please see license.txt 3 | 4 | # import frappe 5 | from frappe.model.document import Document 6 | from textile.utils import validate_textile_item 7 | 8 | 9 | class FabricPrinter(Document): 10 | def validate(self): 11 | if self.get("process_item"): 12 | validate_textile_item(self.process_item, "Print Process") 13 | -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/fabric_printer/test_fabric_printer.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, ParaLogic and Contributors 2 | # See license.txt 3 | 4 | # import frappe 5 | from frappe.tests.utils import FrappeTestCase 6 | 7 | 8 | class TestFabricPrinter(FrappeTestCase): 9 | pass 10 | -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/fabric_printing_settings/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/fabric_printing/doctype/fabric_printing_settings/__init__.py -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/fabric_printing_settings/fabric_printing_settings.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, ParaLogic and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('Fabric Printing Settings', { 5 | onload: function(frm) { 6 | erpnext.queries.setup_queries(frm, "Warehouse", function(fieldname) { 7 | return erpnext.queries.warehouse(frm.doc); 8 | }); 9 | 10 | frm.set_query("default_printing_cost_center", function(doc) { 11 | return { 12 | filters: { 13 | "is_group": 0 14 | } 15 | }; 16 | }); 17 | 18 | frm.set_query("stock_entry_type_for_fabric_transfer", function(doc) { 19 | return { 20 | filters: { 21 | purpose: "Material Transfer for Manufacture", 22 | } 23 | }; 24 | }); 25 | frm.set_query("stock_entry_type_for_print_production", function(doc) { 26 | return { 27 | filters: { 28 | purpose: "Manufacture", 29 | } 30 | }; 31 | }); 32 | frm.set_query("stock_entry_type_for_fabric_coating", function(doc) { 33 | return { 34 | filters: { 35 | purpose: "Manufacture", 36 | } 37 | }; 38 | }); 39 | frm.set_query("stock_entry_type_for_fabric_shrinkage", function(doc) { 40 | return { 41 | filters: { 42 | purpose: "Material Issue", 43 | } 44 | }; 45 | }); 46 | frm.set_query("stock_entry_type_for_fabric_rejection", function(doc) { 47 | return { 48 | filters: { 49 | purpose: "Material Transfer", 50 | } 51 | }; 52 | }); 53 | } 54 | }); 55 | -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/fabric_printing_settings/fabric_printing_settings.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, ParaLogic and contributors 2 | # For license information, please see license.txt 3 | 4 | import frappe 5 | from frappe.model.document import Document 6 | 7 | 8 | class FabricPrintingSettings(Document): 9 | def validate(self): 10 | self.update_global_defaults() 11 | 12 | def update_global_defaults(self): 13 | global_default_fields = [ 14 | "default_printing_fabric_warehouse", 15 | "default_printing_source_warehouse", 16 | "default_printing_wip_warehouse", 17 | "default_printing_fg_warehouse", 18 | "default_coating_fg_warehouse", 19 | "default_printing_cost_center", 20 | "default_coating_cost_center", 21 | ] 22 | 23 | for fn in global_default_fields: 24 | frappe.db.set_default(fn, self.get(fn, '')) 25 | -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/fabric_printing_settings/test_fabric_printing_settings.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, ParaLogic and Contributors 2 | # See license.txt 3 | 4 | # import frappe 5 | from frappe.tests.utils import FrappeTestCase 6 | 7 | 8 | class TestFabricPrintingSettings(FrappeTestCase): 9 | pass 10 | -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/print_order/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/fabric_printing/doctype/print_order/__init__.py -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/print_order/print_order_dashboard.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | from frappe import _ 3 | 4 | 5 | def get_data(): 6 | 7 | return { 8 | 'fieldname': 'print_order', 9 | 'internal_links': { 10 | 'Item': ['items', 'item_code'], 11 | 'BOM': ['items', 'design_bom'], 12 | }, 13 | 'transactions': [ 14 | { 15 | 'label': _("Design Item"), 16 | 'items': ['Item', 'BOM'] 17 | }, 18 | { 19 | 'label': _("Order & Billing"), 20 | 'items': ['Sales Order', 'Sales Invoice'] 21 | }, 22 | { 23 | 'label': _("Production"), 24 | 'items': ['Work Order', 'Stock Entry'] 25 | }, 26 | { 27 | 'label': _("Delivery"), 28 | 'items': ['Packing Slip', 'Delivery Note'] 29 | } 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/print_order/print_order_list.js: -------------------------------------------------------------------------------- 1 | frappe.listview_settings['Print Order'] = { 2 | add_fields: ["status"], 3 | 4 | get_indicator: function(doc) { 5 | if (doc.status === "Not Started") { 6 | return [__(doc.status), "yellow", "status,=," + doc.status]; 7 | } else if(doc.status === "To Produce") { 8 | return [__(doc.status), "purple", "status,=," + doc.status]; 9 | } else if(doc.status === "To Deliver") { 10 | return [__(doc.status), "orange", "status,=," + doc.status]; 11 | } else if(doc.status === "To Bill") { 12 | return [__(doc.status), "yellow", "status,=," + doc.status]; 13 | } else if(doc.status === "To Close") { 14 | return [__(doc.status), "blue", "status,=," + doc.status]; 15 | } else if(["Completed", "Closed"].includes(doc.status)) { 16 | return [__(doc.status), "green", "status,=," + doc.status]; 17 | } 18 | }, 19 | 20 | onload: function(listview) { 21 | var method = "textile.fabric_printing.doctype.print_order.print_order.close_or_unclose_print_orders"; 22 | 23 | if (listview.can_write) { 24 | listview.page.add_action_item(__("Close"), function () { 25 | listview.call_for_selected_items(method, {"status": "Closed"}); 26 | }); 27 | 28 | listview.page.add_action_item(__("Re-Open"), function () { 29 | listview.call_for_selected_items(method, {"status": "Submitted"}); 30 | }); 31 | } 32 | 33 | if (listview.page.fields_dict.fabric_item) { 34 | listview.page.fields_dict.fabric_item.get_query = () => { 35 | return erpnext.queries.item({"textile_item_type": "Ready Fabric", "include_disabled": 1}); 36 | } 37 | } 38 | 39 | if (listview.page.fields_dict.process_item) { 40 | listview.page.fields_dict.process_item.get_query = () => { 41 | return erpnext.queries.item({"textile_item_type": "Print Process", "include_disabled": 1}); 42 | } 43 | } 44 | }, 45 | }; 46 | -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/print_order/test_print_order.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, ParaLogic and Contributors 2 | # See license.txt 3 | 4 | # import frappe 5 | from frappe.tests.utils import FrappeTestCase 6 | 7 | 8 | class TestPrintOrder(FrappeTestCase): 9 | pass 10 | -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/print_order_item/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/fabric_printing/doctype/print_order_item/__init__.py -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/print_order_item/print_order_item.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, ParaLogic and contributors 2 | # For license information, please see license.txt 3 | 4 | # import frappe 5 | from frappe.model.document import Document 6 | 7 | class PrintOrderItem(Document): 8 | pass 9 | -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/print_pricing_rule/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/fabric_printing/doctype/print_pricing_rule/__init__.py -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/print_pricing_rule/print_pricing_rule.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024, ParaLogic and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('Print Pricing Rule', { 5 | setup: function(frm) { 6 | frm.set_query("price_list", () => { 7 | return { 8 | filters: { 9 | selling: 1 10 | } 11 | } 12 | }) 13 | } 14 | }); 15 | -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/print_pricing_rule/print_pricing_rule.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "allow_rename": 1, 4 | "autoname": "field:print_pricing_rule_name", 5 | "creation": "2024-01-24 00:24:44.968906", 6 | "default_view": "List", 7 | "doctype": "DocType", 8 | "editable_grid": 1, 9 | "engine": "InnoDB", 10 | "field_order": [ 11 | "print_pricing_rule_name", 12 | "filter_criteria_section", 13 | "price_list", 14 | "customer_group", 15 | "column_break_jdhll", 16 | "fabric_material", 17 | "fabric_type", 18 | "column_break_qefhw", 19 | "fabric_width_lower_limit", 20 | "fabric_width_upper_limit", 21 | "column_break_auf3m", 22 | "fabric_gsm_lower_limit", 23 | "fabric_gsm_upper_limit", 24 | "pricing_section", 25 | "type", 26 | "column_break_jq8di", 27 | "value" 28 | ], 29 | "fields": [ 30 | { 31 | "fieldname": "print_pricing_rule_name", 32 | "fieldtype": "Data", 33 | "label": "Print Pricing Rule Name", 34 | "reqd": 1, 35 | "unique": 1 36 | }, 37 | { 38 | "fieldname": "filter_criteria_section", 39 | "fieldtype": "Section Break", 40 | "label": "Filter Criteria" 41 | }, 42 | { 43 | "fieldname": "fabric_material", 44 | "fieldtype": "Link", 45 | "in_standard_filter": 1, 46 | "label": "Fabric Material", 47 | "options": "Fabric Material" 48 | }, 49 | { 50 | "fieldname": "fabric_type", 51 | "fieldtype": "Link", 52 | "in_standard_filter": 1, 53 | "label": "Fabric Type", 54 | "options": "Fabric Type" 55 | }, 56 | { 57 | "fieldname": "column_break_qefhw", 58 | "fieldtype": "Column Break" 59 | }, 60 | { 61 | "fieldname": "fabric_gsm_lower_limit", 62 | "fieldtype": "Float", 63 | "label": "Fabric GSM Lower Limit", 64 | "non_negative": 1, 65 | "precision": "1" 66 | }, 67 | { 68 | "fieldname": "fabric_gsm_upper_limit", 69 | "fieldtype": "Float", 70 | "label": "Fabric GSM Upper Limit", 71 | "non_negative": 1, 72 | "precision": "1" 73 | }, 74 | { 75 | "fieldname": "column_break_auf3m", 76 | "fieldtype": "Column Break" 77 | }, 78 | { 79 | "fieldname": "fabric_width_lower_limit", 80 | "fieldtype": "Float", 81 | "label": "Fabric Width Lower Limit", 82 | "non_negative": 1, 83 | "precision": "1" 84 | }, 85 | { 86 | "fieldname": "fabric_width_upper_limit", 87 | "fieldtype": "Float", 88 | "label": "Fabric Width Upper Limit", 89 | "non_negative": 1, 90 | "precision": "1" 91 | }, 92 | { 93 | "fieldname": "pricing_section", 94 | "fieldtype": "Section Break", 95 | "label": "Pricing" 96 | }, 97 | { 98 | "fieldname": "column_break_jq8di", 99 | "fieldtype": "Column Break" 100 | }, 101 | { 102 | "fieldname": "value", 103 | "fieldtype": "Float", 104 | "in_list_view": 1, 105 | "label": "Value", 106 | "reqd": 1 107 | }, 108 | { 109 | "fieldname": "column_break_jdhll", 110 | "fieldtype": "Column Break" 111 | }, 112 | { 113 | "fieldname": "customer_group", 114 | "fieldtype": "Link", 115 | "in_standard_filter": 1, 116 | "label": "Customer Group", 117 | "options": "Customer Group" 118 | }, 119 | { 120 | "fieldname": "price_list", 121 | "fieldtype": "Link", 122 | "in_list_view": 1, 123 | "in_standard_filter": 1, 124 | "label": "Price List", 125 | "options": "Price List", 126 | "reqd": 1 127 | }, 128 | { 129 | "fieldname": "type", 130 | "fieldtype": "Select", 131 | "in_list_view": 1, 132 | "in_standard_filter": 1, 133 | "label": "Type", 134 | "options": "\nBase Rate\nAdd/Subtract\nMultiply", 135 | "reqd": 1 136 | } 137 | ], 138 | "index_web_pages_for_search": 1, 139 | "links": [], 140 | "modified": "2024-03-19 18:25:09.345114", 141 | "modified_by": "Administrator", 142 | "module": "Fabric Printing", 143 | "name": "Print Pricing Rule", 144 | "naming_rule": "By fieldname", 145 | "owner": "Administrator", 146 | "permissions": [ 147 | { 148 | "create": 1, 149 | "delete": 1, 150 | "email": 1, 151 | "export": 1, 152 | "print": 1, 153 | "read": 1, 154 | "report": 1, 155 | "role": "System Manager", 156 | "share": 1, 157 | "write": 1 158 | }, 159 | { 160 | "email": 1, 161 | "export": 1, 162 | "print": 1, 163 | "read": 1, 164 | "report": 1, 165 | "role": "Invoice User", 166 | "share": 1 167 | }, 168 | { 169 | "email": 1, 170 | "export": 1, 171 | "print": 1, 172 | "read": 1, 173 | "report": 1, 174 | "role": "Accounts User", 175 | "share": 1 176 | } 177 | ], 178 | "sort_field": "modified", 179 | "sort_order": "DESC", 180 | "states": [], 181 | "track_changes": 1 182 | } -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/print_pricing_rule/print_pricing_rule.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, ParaLogic and contributors 2 | # For license information, please see license.txt 3 | 4 | import frappe 5 | from frappe.utils import flt 6 | from textile.controllers.textile_pricing_rule import TextilePricingRule 7 | from erpnext.stock.doctype.item.item import convert_item_uom_for 8 | 9 | 10 | class PrintPricingRule(TextilePricingRule): 11 | doctype = "Print Pricing Rule" 12 | cache_field = "print_pricing_rule_names" 13 | 14 | @classmethod 15 | def get_customer_base_rate(cls, customer): 16 | return flt(frappe.get_cached_value("Customer", customer, "base_printing_rate")) 17 | 18 | @classmethod 19 | def is_fixed_base_rate(cls, customer): 20 | return frappe.get_cached_value("Customer", customer, "is_fixed_printing_rate") 21 | 22 | 23 | @frappe.whitelist() 24 | def get_printing_rate(design_item, price_list, customer=None, uom=None, conversion_factor=None): 25 | printing_rate = PrintPricingRule.get_applied_rule(design_item, price_list, customer)["rule_rate"] 26 | 27 | item = frappe.get_cached_doc("Item", design_item) 28 | if uom and uom != item.stock_uom: 29 | printing_rate = convert_item_uom_for( 30 | value=printing_rate, 31 | item_code=item.name, 32 | from_uom=item.stock_uom, 33 | to_uom=uom, 34 | conversion_factor=conversion_factor, 35 | is_rate=True 36 | ) 37 | 38 | return printing_rate 39 | 40 | 41 | @frappe.whitelist() 42 | def get_printing_rate_breakup(item_code, price_list, customer=None): 43 | from textile.controllers.textile_pricing_rule import get_fabric_rate 44 | 45 | item = frappe.get_cached_doc("Item", item_code) 46 | if item.textile_item_type == "Printed Design": 47 | fabric_item_code = item.fabric_item 48 | else: 49 | fabric_item_code = item_code 50 | 51 | out = PrintPricingRule.get_applied_rule(item_code, price_list, customer) 52 | fabric_rate = get_fabric_rate(fabric_item_code, price_list, frappe._dict({"customer": customer})) 53 | 54 | out.fabric_rate = fabric_rate 55 | out.price_list_rate = fabric_rate + flt(out.get("rule_rate")) 56 | 57 | out["applied_rules"] = [] 58 | for d in [out.base_rate_rule] + out.addition_rules + out.multiplier_rules: 59 | if not d: 60 | continue 61 | 62 | out.applied_rules.append({ 63 | "rule": d.name, 64 | "customer": d.customer, 65 | "type": d.type, 66 | "value": d.value, 67 | }) 68 | 69 | return out 70 | -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/print_pricing_rule/print_pricing_rule_list.js: -------------------------------------------------------------------------------- 1 | frappe.provide("textile"); 2 | 3 | frappe.listview_settings["Print Pricing Rule"] = { 4 | onload: function(listview) { 5 | listview.page.add_menu_item(__("Check Printing Rate"), () => { 6 | textile.show_print_pricing_dialog(); 7 | }); 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/print_pricing_rule/test_print_pricing_rule.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2024, ParaLogic and Contributors 2 | # See license.txt 3 | 4 | # import frappe 5 | from frappe.tests.utils import FrappeTestCase 6 | 7 | 8 | class TestPrintPricingRule(FrappeTestCase): 9 | pass 10 | -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/print_process_rule/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/fabric_printing/doctype/print_process_rule/__init__.py -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/print_process_rule/print_process_rule.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, ParaLogic and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.provide("textile"); 5 | 6 | textile.PrintProcessRule = class PrintProcessRule extends frappe.ui.form.Controller { 7 | setup() { 8 | this.setup_queries(); 9 | } 10 | 11 | setup_queries() { 12 | this.frm.set_query("process_item", () => { 13 | return erpnext.queries.item({ textile_item_type: 'Print Process' }); 14 | }); 15 | 16 | for (let [component_item_field, component_type] of Object.entries(textile.printing_components)) { 17 | this.frm.set_query(component_item_field, () => { 18 | return erpnext.queries.item({ 19 | textile_item_type: 'Process Component', 20 | process_component: component_type 21 | }); 22 | }); 23 | } 24 | } 25 | } 26 | 27 | extend_cscript(cur_frm.cscript, new textile.PrintProcessRule({frm: cur_frm})); 28 | -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/print_process_rule/test_print_process_rule.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, ParaLogic and Contributors 2 | # See license.txt 3 | 4 | # import frappe 5 | from frappe.tests.utils import FrappeTestCase 6 | 7 | 8 | class TestPrintProcessRule(FrappeTestCase): 9 | pass 10 | -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/printed_fabric_detail/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/fabric_printing/doctype/printed_fabric_detail/__init__.py -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/printed_fabric_detail/printed_fabric_detail.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "allow_rename": 1, 4 | "creation": "2024-02-02 10:47:06.247981", 5 | "doctype": "DocType", 6 | "editable_grid": 1, 7 | "engine": "InnoDB", 8 | "field_order": [ 9 | "fabric_item", 10 | "fabric_item_name", 11 | "is_return_fabric", 12 | "fabric_qty", 13 | "fabric_rate", 14 | "fabric_amount" 15 | ], 16 | "fields": [ 17 | { 18 | "columns": 1, 19 | "fieldname": "fabric_item", 20 | "fieldtype": "Link", 21 | "in_list_view": 1, 22 | "label": "Fabric Item", 23 | "options": "Item", 24 | "read_only": 1, 25 | "reqd": 1 26 | }, 27 | { 28 | "columns": 4, 29 | "fetch_from": "fabric_item.item_name", 30 | "fieldname": "fabric_item_name", 31 | "fieldtype": "Data", 32 | "in_list_view": 1, 33 | "label": "Fabric Item Name", 34 | "read_only": 1 35 | }, 36 | { 37 | "bold": 1, 38 | "columns": 1, 39 | "fieldname": "fabric_qty", 40 | "fieldtype": "Float", 41 | "in_list_view": 1, 42 | "label": "Qty", 43 | "read_only": 1 44 | }, 45 | { 46 | "columns": 1, 47 | "fieldname": "fabric_rate", 48 | "fieldtype": "Currency", 49 | "in_list_view": 1, 50 | "label": "Rate", 51 | "options": "currency", 52 | "precision": "3" 53 | }, 54 | { 55 | "columns": 1, 56 | "fieldname": "fabric_amount", 57 | "fieldtype": "Currency", 58 | "in_list_view": 1, 59 | "label": "Amount", 60 | "options": "currency", 61 | "read_only": 1 62 | }, 63 | { 64 | "default": "0", 65 | "fieldname": "is_return_fabric", 66 | "fieldtype": "Check", 67 | "in_list_view": 1, 68 | "label": "Return Fabric", 69 | "read_only": 1 70 | } 71 | ], 72 | "index_web_pages_for_search": 1, 73 | "istable": 1, 74 | "links": [], 75 | "modified": "2024-05-19 04:02:52.158771", 76 | "modified_by": "Administrator", 77 | "module": "Fabric Printing", 78 | "name": "Printed Fabric Detail", 79 | "owner": "Administrator", 80 | "permissions": [], 81 | "sort_field": "modified", 82 | "sort_order": "DESC", 83 | "states": [] 84 | } -------------------------------------------------------------------------------- /textile/fabric_printing/doctype/printed_fabric_detail/printed_fabric_detail.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2024, ParaLogic and contributors 2 | # For license information, please see license.txt 3 | 4 | # import frappe 5 | from frappe.model.document import Document 6 | 7 | class PrintedFabricDetail(Document): 8 | pass 9 | -------------------------------------------------------------------------------- /textile/fabric_printing/number_card/print_orders_in_production/print_orders_in_production.json: -------------------------------------------------------------------------------- 1 | { 2 | "aggregate_function_based_on": "", 3 | "color": "#761ACB", 4 | "creation": "2023-06-20 12:02:06.256431", 5 | "docstatus": 0, 6 | "doctype": "Number Card", 7 | "document_type": "Print Order", 8 | "dynamic_filters_json": "[]", 9 | "filters_json": "[[\"Print Order\",\"docstatus\",\"=\",\"1\",false],[\"Print Order\",\"status\",\"=\",\"To Produce\",false]]", 10 | "function": "Count", 11 | "idx": 0, 12 | "is_public": 1, 13 | "is_standard": 1, 14 | "label": "Print Orders In Production", 15 | "modified": "2023-09-12 23:02:18.476901", 16 | "modified_by": "Administrator", 17 | "module": "Fabric Printing", 18 | "name": "Print Orders In Production", 19 | "owner": "Administrator", 20 | "parent_document_type": "", 21 | "report_function": "Sum", 22 | "show_percentage_stats": 0, 23 | "stats_time_interval": "Daily", 24 | "type": "Document Type" 25 | } -------------------------------------------------------------------------------- /textile/fabric_printing/number_card/print_orders_to_confirm/print_orders_to_confirm.json: -------------------------------------------------------------------------------- 1 | { 2 | "aggregate_function_based_on": "", 3 | "color": "#ECAD4B", 4 | "creation": "2023-06-20 12:06:06.915228", 5 | "docstatus": 0, 6 | "doctype": "Number Card", 7 | "document_type": "Print Order", 8 | "dynamic_filters_json": "[]", 9 | "filters_json": "[[\"Print Order\",\"status\",\"in\",[\"Draft\",\"Not Started\"],false]]", 10 | "function": "Count", 11 | "idx": 0, 12 | "is_public": 1, 13 | "is_standard": 1, 14 | "label": "Print Orders To Confirm", 15 | "modified": "2024-07-06 14:41:29.581856", 16 | "modified_by": "Administrator", 17 | "module": "Fabric Printing", 18 | "name": "Print Orders To Confirm", 19 | "owner": "Administrator", 20 | "parent_document_type": "", 21 | "report_function": "Sum", 22 | "show_percentage_stats": 1, 23 | "stats_time_interval": "Daily", 24 | "type": "Document Type" 25 | } -------------------------------------------------------------------------------- /textile/fabric_printing/number_card/print_orders_to_deliver/print_orders_to_deliver.json: -------------------------------------------------------------------------------- 1 | { 2 | "aggregate_function_based_on": "", 3 | "color": "#EC864B", 4 | "creation": "2023-06-20 12:07:05.212182", 5 | "docstatus": 0, 6 | "doctype": "Number Card", 7 | "document_type": "Print Order", 8 | "dynamic_filters_json": "[]", 9 | "filters_json": "[[\"Print Order\",\"docstatus\",\"=\",\"1\",false],[\"Print Order\",\"status\",\"=\",\"To Deliver\",false]]", 10 | "function": "Count", 11 | "idx": 0, 12 | "is_public": 1, 13 | "is_standard": 1, 14 | "label": "Print Orders To Deliver", 15 | "modified": "2023-09-12 23:02:20.601260", 16 | "modified_by": "Administrator", 17 | "module": "Fabric Printing", 18 | "name": "Print Orders To Deliver", 19 | "owner": "Administrator", 20 | "parent_document_type": "", 21 | "report_function": "Sum", 22 | "show_percentage_stats": 0, 23 | "stats_time_interval": "Daily", 24 | "type": "Document Type" 25 | } -------------------------------------------------------------------------------- /textile/fabric_printing/number_card/print_orders_to_pack/print_orders_to_pack.json: -------------------------------------------------------------------------------- 1 | { 2 | "aggregate_function_based_on": "", 3 | "color": "#4463F0", 4 | "creation": "2023-06-20 12:11:19.993330", 5 | "docstatus": 0, 6 | "doctype": "Number Card", 7 | "document_type": "Print Order", 8 | "dynamic_filters_json": "[]", 9 | "filters_json": "[[\"Print Order\",\"docstatus\",\"=\",\"1\",false],[\"Print Order\",\"packing_status\",\"=\",\"To Pack\",false]]", 10 | "function": "Count", 11 | "idx": 0, 12 | "is_public": 1, 13 | "is_standard": 1, 14 | "label": "Print Orders To Pack", 15 | "modified": "2023-09-12 23:02:22.176582", 16 | "modified_by": "Administrator", 17 | "module": "Fabric Printing", 18 | "name": "Print Orders To Pack", 19 | "owner": "Administrator", 20 | "parent_document_type": "", 21 | "report_function": "Sum", 22 | "show_percentage_stats": 0, 23 | "stats_time_interval": "Daily", 24 | "type": "Document Type" 25 | } -------------------------------------------------------------------------------- /textile/fabric_printing/page/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/fabric_printing/page/__init__.py -------------------------------------------------------------------------------- /textile/fabric_printing/page/print_order_packing/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/fabric_printing/page/print_order_packing/__init__.py -------------------------------------------------------------------------------- /textile/fabric_printing/page/print_order_packing/print_order_packing.js: -------------------------------------------------------------------------------- 1 | frappe.provide("textile"); 2 | 3 | frappe.pages['print-order-packing'].on_page_show = function(wrapper) { 4 | if (!textile.print_order_packing) { 5 | textile.print_order_packing = new textile.PrintOrderPacking(wrapper); 6 | window.cur_list = textile.print_order_packing.list_view; 7 | } else { 8 | if (textile.print_order_packing?.list_view) { 9 | window.cur_list = textile.print_order_packing.list_view; 10 | textile.print_order_packing.list_view.show(); 11 | } 12 | } 13 | } 14 | 15 | textile.PrintOrderPacking = class PrintOrderPacking { 16 | constructor(wrapper) { 17 | this.page = frappe.ui.make_app_page({ 18 | parent: wrapper, 19 | title: __("Print Order Packing"), 20 | single_column: false 21 | }); 22 | this.parent = wrapper; 23 | 24 | this.make(); 25 | } 26 | 27 | make() { 28 | this.list_view = new textile.PrintOrderPackingList({ 29 | doctype: "Work Order", 30 | parent: this.parent, 31 | }); 32 | } 33 | } 34 | 35 | textile.PrintOrderPackingList = class PrintOrderPackingList extends textile.PrintListView { 36 | page_title = __("Print Order Packing") 37 | check_on_click = true 38 | 39 | setup_defaults() { 40 | let out = super.setup_defaults(); 41 | this.can_create = false; 42 | this.can_write = false; 43 | this.page_length = 100; 44 | return out; 45 | } 46 | 47 | get_args() { 48 | const args = super.get_args(); 49 | 50 | args.filters.push(["Work Order", "packing_slip_required", "=", 1]); 51 | args.filters.push(["Work Order", "docstatus", "=", 1]); 52 | 53 | args.or_filters = [ 54 | ["packing_status", "=", "To Pack"], 55 | ["last_packing_date", "=", frappe.datetime.get_today()], 56 | ]; 57 | 58 | return args; 59 | } 60 | 61 | toggle_actions_menu_button() { 62 | this.page.hide_actions_menu(); 63 | } 64 | 65 | setup_view_menu() { 66 | 67 | } 68 | 69 | get_button_html() { 70 | return ""; 71 | } 72 | 73 | set_primary_action() { 74 | super.set_primary_action(); 75 | this.page.set_primary_action( 76 | __("Create Packing Slip"), 77 | () => this.make_packing_slip(), 78 | "add" 79 | ); 80 | } 81 | 82 | make_packing_slip() { 83 | let work_orders = this.get_checked_items(true); 84 | if (!work_orders || !work_orders.length) { 85 | frappe.throw(__("Please select designs to pack first")); 86 | } 87 | 88 | return frappe.call({ 89 | method: "erpnext.manufacturing.doctype.work_order.work_order.make_packing_slip", 90 | args: { 91 | "work_orders": work_orders, 92 | }, 93 | callback: function (r) { 94 | if (!r.exc) { 95 | var doclist = frappe.model.sync(r.message); 96 | frappe.set_route("Form", doclist[0].doctype, doclist[0].name); 97 | } 98 | } 99 | }); 100 | } 101 | 102 | get_indicator_html(doc) { 103 | const indicator = frappe.get_indicator(doc, this.doctype); 104 | // sequence is important 105 | const docstatus_description = [ 106 | __("Document is in draft state"), 107 | __("Document has been submitted"), 108 | __("Document has been cancelled"), 109 | ]; 110 | const title = docstatus_description[doc.docstatus || 0]; 111 | if (indicator) { 112 | return ` 114 | ${doc.docstatus == 1 ? "Production" : ""} ${__(indicator[0])} 115 | `; 116 | } 117 | return ""; 118 | } 119 | 120 | get_progress_html(doc) { 121 | return erpnext.manufacturing.show_progress_for_packing(doc); 122 | } 123 | 124 | get_details_html(doc) { 125 | return ` 126 |
127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 148 | 149 |
Print Order:${doc.print_order || ""}
Customer:${doc.customer_name || doc.customer || ""}
Fabric:${doc.fabric_item_name || doc.fabric_item || ""}
Packed: 143 | ${this.get_formatted("packed_qty", doc)} 144 | / 145 | ${this.get_formatted("completed_qty", doc)} 146 | Meter 147 |
150 |
151 | `; 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /textile/fabric_printing/page/print_order_packing/print_order_packing.json: -------------------------------------------------------------------------------- 1 | { 2 | "content": null, 3 | "creation": "2023-06-15 23:02:10.743009", 4 | "docstatus": 0, 5 | "doctype": "Page", 6 | "idx": 0, 7 | "modified": "2024-03-19 18:11:21.990536", 8 | "modified_by": "Administrator", 9 | "module": "Fabric Printing", 10 | "name": "print-order-packing", 11 | "owner": "Administrator", 12 | "page_name": "print-order-packing", 13 | "roles": [ 14 | { 15 | "role": "Print Sales User" 16 | }, 17 | { 18 | "role": "Print Production User" 19 | }, 20 | { 21 | "role": "Packing User" 22 | } 23 | ], 24 | "script": null, 25 | "standard": "Yes", 26 | "style": null, 27 | "system_page": 0, 28 | "title": "Print Order Packing" 29 | } -------------------------------------------------------------------------------- /textile/fabric_printing/page/print_work_order/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/fabric_printing/page/print_work_order/__init__.py -------------------------------------------------------------------------------- /textile/fabric_printing/page/print_work_order/print_work_order.js: -------------------------------------------------------------------------------- 1 | frappe.provide("textile"); 2 | 3 | frappe.pages['print-work-order'].on_page_show = function(wrapper) { 4 | if (!textile.print_work_order_list) { 5 | textile.print_work_order_list = new textile.PrintWorkOrder(wrapper); 6 | window.cur_list = textile.print_work_order_list.list_view; 7 | } else { 8 | if (textile.print_work_order_list?.list_view) { 9 | window.cur_list = textile.print_work_order_list.list_view; 10 | textile.print_work_order_list.list_view.show(); 11 | } 12 | } 13 | } 14 | 15 | textile.PrintWorkOrder = class PrintWorkOrder { 16 | constructor(wrapper) { 17 | this.page = frappe.ui.make_app_page({ 18 | parent: wrapper, 19 | title: __("Print Work Order"), 20 | single_column: false 21 | }); 22 | this.parent = wrapper; 23 | 24 | this.make(); 25 | } 26 | 27 | make() { 28 | this.list_view = new textile.PrintWorkOrderList({ 29 | doctype: "Work Order", 30 | parent: this.parent, 31 | }); 32 | } 33 | } 34 | 35 | textile.PrintWorkOrderList = class PrintWorkOrderList extends textile.PrintListView { 36 | get_progress_html(doc) { 37 | return erpnext.manufacturing.show_progress_for_production(doc); 38 | } 39 | 40 | get_details_html(doc) { 41 | return ` 42 |
43 |
44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 66 | 67 |
Print Order:${doc.print_order || ""}
Customer:${doc.customer_name || doc.customer || ""}
Fabric:${doc.fabric_item_name || doc.fabric_item || ""}
Produced: 60 | ${this.get_formatted("completed_qty", doc)} 61 | / 62 | ${this.get_formatted("qty", doc)} 63 | ${doc.stock_uom} 64 | (${this.get_formatted("per_produced", doc)}) 65 |
68 |
69 |
70 | `; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /textile/fabric_printing/page/print_work_order/print_work_order.json: -------------------------------------------------------------------------------- 1 | { 2 | "content": null, 3 | "creation": "2023-08-29 12:54:31.421691", 4 | "docstatus": 0, 5 | "doctype": "Page", 6 | "idx": 0, 7 | "modified": "2024-03-19 18:11:43.855515", 8 | "modified_by": "Administrator", 9 | "module": "Fabric Printing", 10 | "name": "print-work-order", 11 | "owner": "Administrator", 12 | "page_name": "print-work-order", 13 | "roles": [ 14 | { 15 | "role": "Print Production User" 16 | }, 17 | { 18 | "role": "Packing User" 19 | } 20 | ], 21 | "script": null, 22 | "standard": "Yes", 23 | "style": null, 24 | "system_page": 0, 25 | "title": "Print Work Order" 26 | } -------------------------------------------------------------------------------- /textile/fabric_printing/report/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/fabric_printing/report/__init__.py -------------------------------------------------------------------------------- /textile/fabric_printing/report/coating_production_register/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/fabric_printing/report/coating_production_register/__init__.py -------------------------------------------------------------------------------- /textile/fabric_printing/report/coating_production_register/coating_production_register.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, ParaLogic and contributors 2 | // For license information, please see license.txt 3 | /* eslint-disable */ 4 | 5 | frappe.provide("textile"); 6 | 7 | textile.group_field_opts_cpr = [ 8 | "", 9 | "Group by Customer", 10 | "Group by Fabric Item", 11 | "Group by Coating Order", 12 | "Group by Coating Item", 13 | ]; 14 | 15 | frappe.query_reports["Coating Production Register"] = { 16 | "filters": [ 17 | { 18 | fieldname: "company", 19 | label: __("Company"), 20 | fieldtype: "Link", 21 | options: "Company", 22 | default: frappe.defaults.get_user_default("Company"), 23 | reqd: 1, 24 | }, 25 | { 26 | fieldname: "from_date", 27 | label: __("From Date"), 28 | fieldtype: "Date", 29 | default: frappe.datetime.month_start(), 30 | reqd: 1 31 | }, 32 | { 33 | fieldname: "to_date", 34 | label: __("To Date"), 35 | fieldtype: "Date", 36 | default: frappe.datetime.month_end(), 37 | reqd: 1 38 | }, 39 | { 40 | fieldname: "fabric_item", 41 | label: __("Fabric Item"), 42 | fieldtype: "Link", 43 | options: "Item", 44 | get_query: function() { 45 | return { 46 | query: "erpnext.controllers.queries.item_query", 47 | filters: { 48 | 'textile_item_type': "Ready Fabric" 49 | } 50 | }; 51 | }, 52 | }, 53 | { 54 | fieldname: "fabric_material", 55 | label: __("Fabric Material"), 56 | fieldtype: "Link", 57 | options: "Fabric Material", 58 | }, 59 | { 60 | fieldname: "fabric_type", 61 | label: __("Fabric Type"), 62 | fieldtype: "Link", 63 | options: "Fabric Type", 64 | }, 65 | { 66 | fieldname: "customer_provided_items", 67 | label: __("Customer Provided Fabrics"), 68 | fieldtype: "Select", 69 | options: [ 70 | "", 71 | "Customer Provided Fabrics Only", 72 | "Exclude Customer Provided Fabrics", 73 | ] 74 | }, 75 | { 76 | fieldname: "customer", 77 | label: __("Customer"), 78 | fieldtype: "Link", 79 | options: "Customer", 80 | }, 81 | { 82 | "fieldname":"coating_order", 83 | "label": __("Coating Order"), 84 | "fieldtype": "MultiSelectList", 85 | get_data: function(txt) { 86 | let filters = { 87 | company: frappe.query_report.get_filter_value("company") 88 | } 89 | customer = frappe.query_report.get_filter_value("customer"); 90 | if (customer) { 91 | filters.customer = customer; 92 | } 93 | return frappe.db.get_link_options('Coating Order', txt, filters); 94 | } 95 | }, 96 | { 97 | fieldname: "coating_item", 98 | label: __("Coating Item"), 99 | fieldtype: "Link", 100 | options: "Item", 101 | get_query: function() { 102 | return { 103 | query: "erpnext.controllers.queries.item_query", 104 | filters: { 105 | 'textile_item_type': "Process Component", 106 | 'process_component': "Coating", 107 | } 108 | }; 109 | }, 110 | }, 111 | { 112 | fieldname: "group_by_1", 113 | label: __("Group By Level 1"), 114 | fieldtype: "Select", 115 | options: textile.group_field_opts_cpr, 116 | default: "Group by Fabric Item" 117 | }, 118 | { 119 | fieldname: "group_by_2", 120 | label: __("Group By Level 2"), 121 | fieldtype: "Select", 122 | options: textile.group_field_opts_cpr, 123 | default: "" 124 | }, 125 | { 126 | fieldname: "totals_only", 127 | label: __("Group Totals Only"), 128 | fieldtype: "Check", 129 | }, 130 | ], 131 | initial_depth: 1 132 | }; 133 | -------------------------------------------------------------------------------- /textile/fabric_printing/report/coating_production_register/coating_production_register.json: -------------------------------------------------------------------------------- 1 | { 2 | "add_total_row": 1, 3 | "columns": [], 4 | "creation": "2024-03-04 16:10:28.932748", 5 | "disable_prepared_report": 0, 6 | "disabled": 0, 7 | "docstatus": 0, 8 | "doctype": "Report", 9 | "filters": [], 10 | "idx": 0, 11 | "is_standard": "Yes", 12 | "modified": "2024-03-18 15:04:28.254990", 13 | "modified_by": "Administrator", 14 | "module": "Fabric Printing", 15 | "name": "Coating Production Register", 16 | "owner": "Administrator", 17 | "prepared_report": 0, 18 | "ref_doctype": "Coating Order", 19 | "report_name": "Coating Production Register", 20 | "report_type": "Script Report", 21 | "roles": [ 22 | { 23 | "role": "Accounts User" 24 | }, 25 | { 26 | "role": "Print Sales User" 27 | } 28 | ] 29 | } -------------------------------------------------------------------------------- /textile/fabric_printing/report/fabric_printing_summary/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/fabric_printing/report/fabric_printing_summary/__init__.py -------------------------------------------------------------------------------- /textile/fabric_printing/report/fabric_printing_summary/fabric_printing_summary.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, ParaLogic and contributors 2 | // For license information, please see license.txt 3 | /* eslint-disable */ 4 | 5 | frappe.query_reports["Fabric Printing Summary"] = { 6 | "filters": [ 7 | { 8 | fieldname: "from_date", 9 | label: __("From Date"), 10 | fieldtype: "Date", 11 | default: frappe.datetime.month_start(), 12 | reqd: 1 13 | }, 14 | { 15 | fieldname: "to_date", 16 | label: __("To Date"), 17 | fieldtype: "Date", 18 | default: frappe.datetime.month_end(), 19 | reqd: 1 20 | } 21 | ] 22 | }; 23 | -------------------------------------------------------------------------------- /textile/fabric_printing/report/fabric_printing_summary/fabric_printing_summary.json: -------------------------------------------------------------------------------- 1 | { 2 | "add_total_row": 0, 3 | "columns": [], 4 | "creation": "2023-08-15 16:22:43.702795", 5 | "disable_prepared_report": 0, 6 | "disabled": 0, 7 | "docstatus": 0, 8 | "doctype": "Report", 9 | "filters": [], 10 | "idx": 0, 11 | "is_standard": "Yes", 12 | "modified": "2024-03-18 10:17:22.571757", 13 | "modified_by": "Administrator", 14 | "module": "Fabric Printing", 15 | "name": "Fabric Printing Summary", 16 | "owner": "Administrator", 17 | "prepared_report": 0, 18 | "ref_doctype": "Print Order", 19 | "report_name": "Fabric Printing Summary", 20 | "report_type": "Script Report", 21 | "roles": [ 22 | { 23 | "role": "Print Sales User" 24 | }, 25 | { 26 | "role": "Accounts User" 27 | } 28 | ] 29 | } -------------------------------------------------------------------------------- /textile/fabric_printing/report/print_production_register/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/fabric_printing/report/print_production_register/__init__.py -------------------------------------------------------------------------------- /textile/fabric_printing/report/print_production_register/print_production_register.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, ParaLogic and contributors 2 | // For license information, please see license.txt 3 | /* eslint-disable */ 4 | 5 | frappe.provide("textile"); 6 | 7 | textile.group_field_opts_printpr = [ 8 | "", 9 | "Group by Customer", 10 | "Group by Fabric Item", 11 | "Group by Print Order", 12 | "Group by Process Item", 13 | "Group by Fabric Printer", 14 | ] 15 | 16 | frappe.query_reports["Print Production Register"] = { 17 | "filters": [ 18 | { 19 | fieldname: "company", 20 | label: __("Company"), 21 | fieldtype: "Link", 22 | options: "Company", 23 | default: frappe.defaults.get_user_default("Company"), 24 | reqd: 1, 25 | }, 26 | { 27 | fieldname: "from_date", 28 | label: __("From Date"), 29 | fieldtype: "Date", 30 | default: frappe.datetime.month_start(), 31 | reqd: 1 32 | }, 33 | { 34 | fieldname: "to_date", 35 | label: __("To Date"), 36 | fieldtype: "Date", 37 | default: frappe.datetime.month_end(), 38 | reqd: 1 39 | }, 40 | { 41 | fieldname: "fabric_item", 42 | label: __("Fabric Item"), 43 | fieldtype: "Link", 44 | options: "Item", 45 | get_query: function() { 46 | return { 47 | query: "erpnext.controllers.queries.item_query", 48 | filters: { 49 | 'textile_item_type': "Ready Fabric" 50 | } 51 | }; 52 | }, 53 | }, 54 | { 55 | fieldname: "fabric_material", 56 | label: __("Fabric Material"), 57 | fieldtype: "Link", 58 | options: "Fabric Material", 59 | }, 60 | { 61 | fieldname: "fabric_type", 62 | label: __("Fabric Type"), 63 | fieldtype: "Link", 64 | options: "Fabric Type", 65 | }, 66 | { 67 | fieldname: "customer_provided_items", 68 | label: __("Customer Provided Fabrics"), 69 | fieldtype: "Select", 70 | options: [ 71 | "", 72 | "Customer Provided Fabrics Only", 73 | "Exclude Customer Provided Fabrics", 74 | ] 75 | }, 76 | { 77 | fieldname: "customer", 78 | label: __("Customer"), 79 | fieldtype: "Link", 80 | options: "Customer", 81 | }, 82 | { 83 | "fieldname":"print_order", 84 | "label": __("Print Order"), 85 | "fieldtype": "MultiSelectList", 86 | get_data: function(txt) { 87 | let filters = { 88 | company: frappe.query_report.get_filter_value("company") 89 | } 90 | customer = frappe.query_report.get_filter_value("customer"); 91 | if (customer) { 92 | filters.customer = customer; 93 | } 94 | return frappe.db.get_link_options('Print Order', txt, filters); 95 | } 96 | }, 97 | { 98 | fieldname: "process_item", 99 | label: __("Print Process"), 100 | fieldtype: "Link", 101 | options: "Item", 102 | get_query: function() { 103 | return { 104 | query: "erpnext.controllers.queries.item_query", 105 | filters: { 106 | 'textile_item_type': "Print Process" 107 | } 108 | }; 109 | }, 110 | }, 111 | { 112 | fieldname: "softener_item", 113 | label: __("Softener Item"), 114 | fieldtype: "Link", 115 | options: "Item", 116 | get_query: function() { 117 | return { 118 | query: "erpnext.controllers.queries.item_query", 119 | filters: { 120 | 'textile_item_type': "Process Component", 121 | 'process_component': "Softener", 122 | } 123 | }; 124 | }, 125 | }, 126 | { 127 | "fieldname":"fabric_printer", 128 | "label": __("Fabric Printer"), 129 | "fieldtype": "Link", 130 | "options": "Fabric Printer", 131 | get_query: function() { 132 | let process_item = frappe.query_report.get_filter_value("process_item"); 133 | let filters = process_item ? {process_item: process_item} : {} 134 | return { 135 | filters: filters 136 | } 137 | }, 138 | }, 139 | { 140 | fieldname: "group_by_1", 141 | label: __("Group By Level 1"), 142 | fieldtype: "Select", 143 | options: textile.group_field_opts_printpr, 144 | default: "Group by Process Item" 145 | }, 146 | { 147 | fieldname: "group_by_2", 148 | label: __("Group By Level 2"), 149 | fieldtype: "Select", 150 | options: textile.group_field_opts_printpr, 151 | default: "Group by Fabric Printer" 152 | }, 153 | { 154 | fieldname: "group_by_3", 155 | label: __("Group By Level 3"), 156 | fieldtype: "Select", 157 | options: textile.group_field_opts_printpr, 158 | default: "" 159 | }, 160 | { 161 | fieldname: "totals_only", 162 | label: __("Group Totals Only"), 163 | fieldtype: "Check", 164 | }, 165 | ], 166 | initial_depth: 2 167 | }; 168 | -------------------------------------------------------------------------------- /textile/fabric_printing/report/print_production_register/print_production_register.json: -------------------------------------------------------------------------------- 1 | { 2 | "add_total_row": 1, 3 | "columns": [], 4 | "creation": "2023-08-02 18:05:53.797278", 5 | "disable_prepared_report": 0, 6 | "disabled": 0, 7 | "docstatus": 0, 8 | "doctype": "Report", 9 | "filters": [], 10 | "idx": 0, 11 | "is_standard": "Yes", 12 | "modified": "2024-03-18 15:12:36.300257", 13 | "modified_by": "Administrator", 14 | "module": "Fabric Printing", 15 | "name": "Print Production Register", 16 | "owner": "Administrator", 17 | "prepared_report": 0, 18 | "ref_doctype": "Print Order", 19 | "report_name": "Print Production Register", 20 | "report_type": "Script Report", 21 | "roles": [ 22 | { 23 | "role": "Accounts User" 24 | }, 25 | { 26 | "role": "Print Sales User" 27 | } 28 | ] 29 | } -------------------------------------------------------------------------------- /textile/fixtures/property_setter.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "creation": "2024-03-10 16:56:17.427229", 4 | "default_value": null, 5 | "doc_type": "Item", 6 | "docstatus": 0, 7 | "doctype": "Property Setter", 8 | "doctype_or_field": "DocField", 9 | "field_name": "customer", 10 | "is_system_generated": 0, 11 | "modified": "2023-09-21 15:01:39.703909", 12 | "module": null, 13 | "name": "Item-customer-depends_on", 14 | "property": "depends_on", 15 | "property_type": "Data", 16 | "row_name": null, 17 | "value": "eval:doc.is_customer_provided_item || doc.customer || doc.textile_item_type == \"Printed Design\"" 18 | } 19 | ] -------------------------------------------------------------------------------- /textile/modules.txt: -------------------------------------------------------------------------------- 1 | Textile 2 | Fabric Printing 3 | Fabric Pretreatment -------------------------------------------------------------------------------- /textile/notifications.py: -------------------------------------------------------------------------------- 1 | def get_notification_config(): 2 | return { 3 | "for_doctype": { 4 | "Print Order": { 5 | "status": ("not in", ("Completed", "Closed")), 6 | "docstatus": ("<", 2) 7 | }, 8 | }, 9 | } 10 | -------------------------------------------------------------------------------- /textile/overrides/bom_hooks.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | 3 | 4 | def on_bom_cancel(doc, method): 5 | unlink_from_print_orders(doc) 6 | unlink_from_pretreatment_orders(doc) 7 | 8 | 9 | def unlink_from_print_orders(doc): 10 | print_orders = frappe.db.sql_list(""" 11 | select distinct parent 12 | from `tabPrint Order Item` 13 | where design_bom = %s 14 | """, doc.name) 15 | 16 | if not print_orders: 17 | return 18 | 19 | frappe.db.sql(""" 20 | update `tabPrint Order Item` 21 | set design_bom = null 22 | where design_bom = %s 23 | """, doc.name) 24 | 25 | for name in print_orders: 26 | doc = frappe.get_doc("Print Order", name) 27 | doc.set_item_creation_status(update=True) 28 | doc.notify_update() 29 | 30 | 31 | def unlink_from_pretreatment_orders(doc): 32 | pretreatment_orders = frappe.db.sql_list(""" 33 | select name 34 | from `tabPretreatment Order` 35 | where ready_fabric_bom = %s 36 | """, doc.name) 37 | 38 | if not pretreatment_orders: 39 | return 40 | 41 | frappe.db.sql(""" 42 | update `tabPretreatment Order` 43 | set ready_fabric_bom = null 44 | where ready_fabric_bom = %s 45 | """, doc.name) 46 | -------------------------------------------------------------------------------- /textile/overrides/customer_hooks.js: -------------------------------------------------------------------------------- 1 | frappe.ui.form.on('Customer', { 2 | default_printing_uom(frm) { 3 | if (frm.doc.default_printing_uom == "Panel") { 4 | frm.set_value("default_printing_qty_type", "Print Qty"); 5 | } else { 6 | frm.set_value("default_printing_length_uom", frm.doc.default_printing_uom); 7 | } 8 | } 9 | }); 10 | -------------------------------------------------------------------------------- /textile/overrides/customer_hooks.py: -------------------------------------------------------------------------------- 1 | # import frappe 2 | from frappe import _ 3 | from textile.fabric_printing.doctype.print_order.print_order import validate_uom_and_qty_type 4 | 5 | 6 | def customer_order_default_validate(self, hook): 7 | validate_uom_and_qty_type(self) 8 | 9 | 10 | def override_customer_dashboard(data): 11 | data["transactions"].append({ 12 | "label": _("Textile"), 13 | "items": ["Pretreatment Order", "Print Order"] 14 | }) 15 | return data 16 | -------------------------------------------------------------------------------- /textile/overrides/delivery_note_hooks.js: -------------------------------------------------------------------------------- 1 | frappe.provide("textile"); 2 | 3 | frappe.ui.form.on("Delivery Note", { 4 | refresh: function(frm) { 5 | if (frm.doc.docstatus === 0) { 6 | if (frappe.model.can_read("Pretreatment Order") || frappe.model.can_select("Pretreatment Order")) { 7 | frm.add_custom_button(__('Pretreatment Order'), function () { 8 | textile.get_items_from_pretreatment_order( 9 | frm, 10 | "textile.fabric_pretreatment.doctype.pretreatment_order.pretreatment_order.make_delivery_note", 11 | null, 12 | "textile.fabric_pretreatment.doctype.pretreatment_order.pretreatment_order.get_pretreatment_orders_to_be_delivered" 13 | ); 14 | }, __("Get Items From")); 15 | } 16 | 17 | if (frappe.model.can_read("Print Order") || frappe.model.can_select("Print Order")) { 18 | frm.add_custom_button(__('Print Order'), function () { 19 | textile.get_items_from_print_order(frm, 20 | "textile.fabric_printing.doctype.print_order.print_order.make_delivery_note", 21 | null, 22 | "textile.fabric_printing.doctype.print_order.print_order.get_print_orders_to_be_delivered" 23 | ); 24 | }, __("Get Items From")); 25 | } 26 | } 27 | }, 28 | }); 29 | 30 | frappe.ui.form.on("Delivery Note Item", { 31 | panel_qty: function(frm, cdt, cdn) { 32 | textile.calculate_panel_length_meter(frm, cdt, cdn); 33 | }, 34 | 35 | panel_based_qty: function(frm, cdt, cdn) { 36 | frm.cscript.calculate_taxes_and_totals(); 37 | }, 38 | }); 39 | -------------------------------------------------------------------------------- /textile/overrides/delivery_note_hooks.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | # from frappe import _ 3 | from erpnext.stock.doctype.delivery_note.delivery_note import DeliveryNote 4 | from textile.fabric_printing.doctype.print_order.print_order import validate_transaction_against_print_order 5 | from textile.fabric_pretreatment.doctype.pretreatment_order.pretreatment_order import validate_transaction_against_pretreatment_order 6 | from textile.utils import is_row_return_fabric 7 | 8 | 9 | class DeliveryNoteDP(DeliveryNote): 10 | def __init__(self, *args, **kwargs): 11 | super().__init__(*args, **kwargs) 12 | self.force_item_fields += ["fabric_item", "fabric_item_name", "textile_item_type"] 13 | 14 | def set_missing_values(self, for_validate=False): 15 | super().set_missing_values(for_validate=for_validate) 16 | self.set_is_return_fabric() 17 | 18 | def set_is_return_fabric(self): 19 | for d in self.items: 20 | d.is_return_fabric = is_row_return_fabric(self, d) 21 | 22 | def validate_with_previous_doc(self): 23 | super().validate_with_previous_doc() 24 | validate_transaction_against_pretreatment_order(self) 25 | validate_transaction_against_print_order(self) 26 | 27 | def update_previous_doc_status(self): 28 | super().update_previous_doc_status() 29 | 30 | pretreatment_orders = set([d.pretreatment_order for d in self.items if d.get('pretreatment_order')]) 31 | for name in pretreatment_orders: 32 | doc = frappe.get_doc("Pretreatment Order", name) 33 | doc.set_delivery_status(update=True) 34 | doc.validate_delivered_qty(from_doctype=self.doctype) 35 | 36 | # Update packed qty for unpacked returns 37 | if self.is_return and self.reopen_order: 38 | doc.set_production_packing_status(update=True) 39 | 40 | doc.set_status(update=True) 41 | doc.notify_update() 42 | 43 | print_orders = set([d.print_order for d in self.items if d.get('print_order')]) 44 | print_order_row_names = [d.print_order_item for d in self.items if d.get('print_order_item')] 45 | for name in print_orders: 46 | doc = frappe.get_doc("Print Order", name) 47 | doc.set_delivery_status(update=True) 48 | doc.validate_delivered_qty(from_doctype=self.doctype, row_names=print_order_row_names) 49 | 50 | # Update packed qty for unpacked returns 51 | if self.is_return and self.reopen_order: 52 | doc.set_production_packing_status(update=True) 53 | 54 | doc.set_status(update=True) 55 | doc.notify_update() 56 | 57 | def update_status(self, status): 58 | super().update_status(status) 59 | 60 | pretreatment_orders = set([d.pretreatment_order for d in self.items if d.get('pretreatment_order')]) 61 | for name in pretreatment_orders: 62 | doc = frappe.get_doc("Pretreatment Order", name) 63 | doc.run_method("update_status", None) 64 | 65 | print_orders = set([d.print_order for d in self.items if d.get('print_order')]) 66 | for name in print_orders: 67 | doc = frappe.get_doc("Print Order", name) 68 | doc.run_method("update_status", None) 69 | 70 | def get_skip_sales_invoice(self, row): 71 | is_return_fabric = is_row_return_fabric(self, row) 72 | is_customer_provided = frappe.get_cached_value("Item", row.item_code, "is_customer_provided_item") 73 | if is_return_fabric and is_customer_provided: 74 | return True 75 | 76 | return super().get_skip_sales_invoice(row) 77 | 78 | 79 | def override_delivery_note_dashboard(data): 80 | from textile.utils import override_sales_transaction_dashboard 81 | return override_sales_transaction_dashboard(data) 82 | 83 | 84 | def update_delivery_note_mapper(mapper, target_doctype): 85 | if not mapper.get("Delivery Note Item"): 86 | return 87 | 88 | field_map = mapper["Delivery Note Item"]["field_map"] 89 | 90 | field_map["pretreatment_order"] = "pretreatment_order" 91 | 92 | field_map["print_order"] = "print_order" 93 | field_map["print_order_item"] = "print_order_item" 94 | 95 | 96 | def update_return_mapper(mapper, doctype): 97 | child_dt = f"{doctype} Item" 98 | if not mapper.get(child_dt): 99 | return 100 | 101 | field_map = mapper[child_dt]["field_map"] 102 | 103 | field_map["pretreatment_order"] = "pretreatment_order" 104 | 105 | field_map["print_order"] = "print_order" 106 | field_map["print_order_item"] = "print_order_item" 107 | 108 | if not frappe.flags.args or not frappe.flags.args.reopen_order: 109 | if not frappe.flags.args: 110 | frappe.flags.args = frappe._dict() 111 | 112 | frappe.flags.args.reopen_order = "Yes" 113 | -------------------------------------------------------------------------------- /textile/overrides/item_details_hooks.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | from frappe.utils import cint 3 | 4 | 5 | def get_item_details(args, out, doc=None, for_validate=False): 6 | item = frappe.get_cached_doc("Item", args.item_code) 7 | set_fabric_item_details(args, item, out) 8 | 9 | 10 | def packing_slip_get_item_details(args, out): 11 | item = frappe.get_cached_doc("Item", args.item_code) 12 | set_fabric_item_details(args, item, out) 13 | 14 | 15 | def stock_entry_get_item_details(args, out): 16 | item = frappe.get_cached_doc("Item", args.item_code) 17 | set_fabric_item_details(args, item, out) 18 | 19 | 20 | def set_fabric_item_details(args, item, out): 21 | out.textile_item_type = item.textile_item_type 22 | 23 | if item.textile_item_type in ("Greige Fabric", "Ready Fabric"): 24 | out.update({ 25 | "fabric_item": item.name, 26 | "fabric_item_name": item.item_name, 27 | }) 28 | else: 29 | out.update({ 30 | "fabric_item": item.fabric_item or None, 31 | "fabric_item_name": item.fabric_item_name if item.fabric_item else "", 32 | }) 33 | 34 | if args.get("print_order"): 35 | fabric_details = frappe.db.get_value("Print Order", args.print_order, 36 | ("fabric_item", "fabric_item_name"), as_dict=1, cache=1) or {} 37 | out.update(fabric_details) 38 | 39 | 40 | def get_price_list_rate(item_code, price_list, args): 41 | from textile.fabric_printing.doctype.print_pricing_rule.print_pricing_rule import get_printing_rate 42 | from textile.fabric_pretreatment.doctype.pretreatment_pricing_rule.pretreatment_pricing_rule import \ 43 | get_pretreatment_rate 44 | from textile.controllers.textile_pricing_rule import get_fabric_rate 45 | 46 | if not item_code or not price_list or args.get("selling_or_buying") != "selling": 47 | return 48 | 49 | item = frappe.get_cached_doc("Item", item_code) 50 | customer = args.get("customer") or (args.get("quotation_to") == "Customer" and args.get("party_name")) 51 | 52 | if item.textile_item_type == "Printed Design": 53 | printing_rate = get_printing_rate(item_code, price_list, customer=customer, 54 | uom=args.get("uom"), conversion_factor=args.get("conversion_factor")) 55 | fabric_rate = get_fabric_rate(item.fabric_item, price_list, args) 56 | pretreatment_rate = get_pretreatment_rate_for_printed_fabric(item.fabric_item, price_list, customer, 57 | uom=args.get("uom"), conversion_factor=args.get("conversion_factor")) 58 | return printing_rate + fabric_rate + pretreatment_rate 59 | 60 | elif item.textile_item_type == "Ready Fabric" and args.get("pretreatment_order"): 61 | pretreatment_rate = get_pretreatment_rate(item_code, price_list, customer=customer, 62 | uom=args.get("uom"), conversion_factor=args.get("conversion_factor")) 63 | fabric_rate = get_fabric_rate(item_code, price_list, args) 64 | return pretreatment_rate + fabric_rate 65 | 66 | 67 | def get_pretreatment_rate_for_printed_fabric(ready_fabric_item, price_list, customer, uom, conversion_factor): 68 | from textile.fabric_pretreatment.doctype.pretreatment_pricing_rule.pretreatment_pricing_rule import get_pretreatment_rate 69 | 70 | if ready_fabric_item: 71 | fabric_item_doc = frappe.get_cached_doc("Item", ready_fabric_item) 72 | if fabric_item_doc.is_customer_provided_item and fabric_item_doc.fabric_item: 73 | return get_pretreatment_rate(ready_fabric_item, price_list, 74 | customer=customer, uom=uom, conversion_factor=conversion_factor) 75 | 76 | return 0 77 | -------------------------------------------------------------------------------- /textile/overrides/item_hooks.js: -------------------------------------------------------------------------------- 1 | frappe.ui.form.on('Item', { 2 | setup: function(frm) { 3 | frm.events.setup_custom_queries(frm); 4 | }, 5 | 6 | refresh: function (frm) { 7 | frm.events.set_dynamic_fabric_item_label(frm); 8 | }, 9 | 10 | setup_custom_queries(frm) { 11 | frm.set_query("fabric_item", function() { 12 | let filters = { 13 | textile_item_type: ["in", ["Ready Fabric", "Greige Fabric"]], 14 | }; 15 | 16 | if (frm.doc.textile_item_type == "Printed Design") { 17 | filters.textile_item_type = "Ready Fabric"; 18 | } else if (frm.doc.textile_item_type == "Ready Fabric") { 19 | filters.textile_item_type = "Greige Fabric"; 20 | 21 | if (frm.doc.fabric_material) { 22 | filters.fabric_material = frm.doc.fabric_material; 23 | } 24 | if (frm.doc.fabric_type) { 25 | filters.fabric_type = frm.doc.fabric_type; 26 | } 27 | } 28 | 29 | return erpnext.queries.item(filters); 30 | }); 31 | }, 32 | 33 | textile_item_type(frm) { 34 | frm.events.set_dynamic_fabric_item_label(frm); 35 | 36 | if (!["Ready Fabric", "Printed Design"].includes(frm.doc.textile_item_type) && frm.doc.fabric_item) { 37 | frm.set_value("fabric_item", null) 38 | } 39 | }, 40 | 41 | fabric_item(frm) { 42 | if (frm.doc.textile_item_type == "Printed Design") { 43 | return frm.events.get_fabric_item_details(frm); 44 | } 45 | }, 46 | 47 | get_fabric_item_details(frm) { 48 | return frappe.call({ 49 | method: "textile.utils.get_fabric_item_details", 50 | args: { 51 | fabric_item: frm.doc.fabric_item || "", 52 | }, 53 | callback: (r) => { 54 | if (r.message) { 55 | frm.set_value(r.message); 56 | } 57 | } 58 | }) 59 | }, 60 | 61 | set_dynamic_fabric_item_label(frm) { 62 | let code_label = __("Fabric Item"); 63 | let name_label = __("Fabric Item Name"); 64 | 65 | if (frm.doc.textile_item_type == "Printed Design") { 66 | code_label = __("Ready Fabric Item"); 67 | name_label = __("Ready Fabric Name"); 68 | } else if (frm.doc.textile_item_type == "Ready Fabric") { 69 | code_label = __("Greige Fabric Item"); 70 | name_label = __("Greige Fabric Name"); 71 | } 72 | 73 | frm.set_df_property("fabric_item", "label", code_label); 74 | frm.set_df_property("fabric_item_name", "label", name_label); 75 | } 76 | }); 77 | -------------------------------------------------------------------------------- /textile/overrides/packing_slip_hooks.js: -------------------------------------------------------------------------------- 1 | frappe.provide("textile"); 2 | 3 | frappe.ui.form.on("Packing Slip", { 4 | setup: function(frm) { 5 | frm.cscript.calculate_total_hooks.push(textile.calculate_panel_qty); 6 | }, 7 | 8 | refresh: function(frm) { 9 | if (frm.doc.docstatus === 0) { 10 | if (frappe.model.can_read("Pretreatment Order") || frappe.model.can_select("Pretreatment Order")) { 11 | frm.add_custom_button(__('Pretreatment Order'), function () { 12 | textile.get_items_from_pretreatment_order( 13 | frm, 14 | "textile.fabric_pretreatment.doctype.pretreatment_order.pretreatment_order.make_packing_slip", 15 | {packing_status: "To Pack"} 16 | ); 17 | }, __("Get Items From")); 18 | } 19 | 20 | if (frappe.model.can_read("Print Order") || frappe.model.can_select("Print Order")) { 21 | frm.add_custom_button(__('Print Order'), function () { 22 | textile.get_items_from_print_order( 23 | frm, 24 | "textile.fabric_printing.doctype.print_order.print_order.make_packing_slip", 25 | {packing_status: "To Pack"} 26 | ); 27 | }, __("Get Items From")); 28 | } 29 | 30 | frm.fields_dict.items.grid.add_custom_button(__("Add Return Fabric"), function () { 31 | return frm.call("add_return_fabric"); 32 | }); 33 | } 34 | }, 35 | }); 36 | 37 | frappe.ui.form.on("Packing Slip Item", { 38 | panel_qty: function(frm, cdt, cdn) { 39 | textile.calculate_panel_length_meter(frm, cdt, cdn); 40 | }, 41 | 42 | panel_based_qty: function(frm, cdt, cdn) { 43 | frm.cscript.calculate_totals(); 44 | }, 45 | }); 46 | -------------------------------------------------------------------------------- /textile/overrides/purchase_hooks.py: -------------------------------------------------------------------------------- 1 | from frappe import _ 2 | 3 | 4 | def update_purchase_order_from_work_order(purchase_order, row, work_order): 5 | row.pretreatment_order = work_order.get("pretreatment_order") 6 | 7 | 8 | def update_purchase_order_mapper(mapper, target_doctype): 9 | if not mapper.get("Purchase Order Item"): 10 | return 11 | 12 | field_map = mapper["Purchase Order Item"]["field_map"] 13 | 14 | field_map["pretreatment_order"] = "pretreatment_order" 15 | 16 | field_map["print_order"] = "print_order" 17 | field_map["print_order_item"] = "print_order_item" 18 | 19 | 20 | def update_purchase_receipt_mapper(mapper, target_doctype): 21 | if not mapper.get("Purchase Receipt Item"): 22 | return 23 | 24 | field_map = mapper["Purchase Receipt Item"]["field_map"] 25 | 26 | field_map["pretreatment_order"] = "pretreatment_order" 27 | 28 | field_map["print_order"] = "print_order" 29 | field_map["print_order_item"] = "print_order_item" 30 | 31 | 32 | def override_purchase_order_dashboard(data): 33 | return override_purchase_transaction_dashboard(data, "Purchase Order") 34 | 35 | 36 | def override_purchase_receipt_dashboard(data): 37 | return override_purchase_transaction_dashboard(data, "Purchase Receipt") 38 | 39 | 40 | def override_purchase_invoice_dashboard(data): 41 | return override_purchase_transaction_dashboard(data, "Purchase Invoice") 42 | 43 | 44 | def override_purchase_transaction_dashboard(data, doctype): 45 | data["internal_links"]["Pretreatment Order"] = ["items", "pretreatment_order"] 46 | data["internal_links"]["Print Order"] = ["items", "print_order"] 47 | 48 | textile_items = ["Pretreatment Order"] 49 | 50 | ref_section = [d for d in data["transactions"] if d["label"] == _("Reference")] 51 | if ref_section and doctype == "Purchase Invoice": 52 | ref_section = ref_section[0] 53 | ref_section["items"] = textile_items + ref_section["items"] 54 | else: 55 | data["transactions"].append({ 56 | "label": _("Textile"), 57 | "items": textile_items 58 | }) 59 | 60 | return data 61 | -------------------------------------------------------------------------------- /textile/overrides/purchase_order_hooks.js: -------------------------------------------------------------------------------- 1 | frappe.provide("textile"); 2 | 3 | frappe.ui.form.on("Purchase Order", { 4 | refresh: function(frm) { 5 | if (frm.doc.docstatus === 0) { 6 | if (frappe.model.can_read("Pretreatment Order") || frappe.model.can_select("Pretreatment Order")) { 7 | frm.add_custom_button(__('Pretreatment Order'), function () { 8 | textile.get_items_from_pretreatment_order( 9 | frm, 10 | "textile.fabric_pretreatment.doctype.pretreatment_order.pretreatment_order.make_purchase_order", 11 | {production_status: "To Produce", subcontractable_qty: [">", 0]} 12 | ); 13 | }, __("Get Items From")); 14 | } 15 | } 16 | }, 17 | }); 18 | -------------------------------------------------------------------------------- /textile/overrides/quotation_hooks.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | from erpnext.selling.doctype.quotation.quotation import Quotation 3 | 4 | 5 | class QuotationDP(Quotation): 6 | def __init__(self, *args, **kwargs): 7 | super().__init__(*args, **kwargs) 8 | self.force_item_fields += ["textile_item_type"] 9 | -------------------------------------------------------------------------------- /textile/overrides/sales_invoice_hooks.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | # from frappe import _ 3 | from erpnext.accounts.doctype.sales_invoice.sales_invoice import SalesInvoice 4 | from textile.fabric_printing.doctype.print_order.print_order import validate_transaction_against_print_order 5 | from textile.fabric_pretreatment.doctype.pretreatment_order.pretreatment_order import validate_transaction_against_pretreatment_order 6 | from textile.utils import is_row_return_fabric 7 | 8 | 9 | class SalesInvoiceDP(SalesInvoice): 10 | def __init__(self, *args, **kwargs): 11 | super().__init__(*args, **kwargs) 12 | self.force_item_fields += ["fabric_item", "fabric_item_name", "textile_item_type"] 13 | 14 | def set_missing_values(self, for_validate=False): 15 | super().set_missing_values(for_validate=for_validate) 16 | self.set_is_return_fabric() 17 | 18 | def set_is_return_fabric(self): 19 | for d in self.items: 20 | d.is_return_fabric = is_row_return_fabric(self, d) 21 | 22 | def validate_with_previous_doc(self): 23 | super().validate_with_previous_doc() 24 | validate_transaction_against_pretreatment_order(self) 25 | validate_transaction_against_print_order(self) 26 | 27 | def update_previous_doc_status(self): 28 | super().update_previous_doc_status() 29 | 30 | if self.update_stock: 31 | pretreatment_orders = set([d.pretreatment_order for d in self.items if d.get('pretreatment_order')]) 32 | for name in pretreatment_orders: 33 | doc = frappe.get_doc("Pretreatment Order", name) 34 | doc.set_delivery_status(update=True) 35 | doc.validate_delivered_qty(from_doctype=self.doctype) 36 | doc.set_status(update=True) 37 | 38 | # Update packed qty for unpacked returns 39 | if self.is_return and self.reopen_order: 40 | doc.set_production_packing_status(update=True) 41 | 42 | doc.notify_update() 43 | 44 | print_orders = set([d.print_order for d in self.items if d.get('print_order')]) 45 | print_order_row_names = [d.print_order_item for d in self.items if d.get('print_order_item')] 46 | for name in print_orders: 47 | doc = frappe.get_doc("Print Order", name) 48 | doc.set_delivery_status(update=True) 49 | doc.validate_delivered_qty(from_doctype=self.doctype, row_names=print_order_row_names) 50 | 51 | # Update packed qty for unpacked returns 52 | if self.is_return and self.reopen_order: 53 | doc.set_production_packing_status(update=True) 54 | 55 | doc.set_status(update=True) 56 | doc.notify_update() 57 | 58 | 59 | def override_sales_invoice_dashboard(data): 60 | from textile.utils import override_sales_transaction_dashboard 61 | return override_sales_transaction_dashboard(data) 62 | -------------------------------------------------------------------------------- /textile/overrides/sales_order_hooks.js: -------------------------------------------------------------------------------- 1 | frappe.provide("textile"); 2 | 3 | frappe.ui.form.on("Sales Order", { 4 | refresh: function(frm) { 5 | if (frm.doc.docstatus === 0) { 6 | if (frappe.model.can_read("Pretreatment Order") || frappe.model.can_select("Pretreatment Order")) { 7 | frm.add_custom_button(__('Pretreatment Order'), function () { 8 | textile.get_items_from_pretreatment_order( 9 | frm, 10 | "textile.fabric_pretreatment.doctype.pretreatment_order.pretreatment_order.make_sales_order", 11 | {per_ordered: ["<", 100]} 12 | ); 13 | }, __("Get Items From")); 14 | } 15 | 16 | if (frappe.model.can_read("Print Order") || frappe.model.can_select("Print Order")) { 17 | frm.add_custom_button(__('Print Order'), function () { 18 | textile.get_items_from_print_order( 19 | frm, 20 | "textile.fabric_printing.doctype.print_order.print_order.make_sales_order", 21 | {per_ordered: ["<", 100]} 22 | ); 23 | }, __("Get Items From")); 24 | } 25 | } 26 | }, 27 | }); 28 | 29 | frappe.ui.form.on("Sales Order Item", { 30 | panel_qty: function(frm, cdt, cdn) { 31 | textile.calculate_panel_length_meter(frm, cdt, cdn); 32 | }, 33 | 34 | panel_based_qty: function(frm, cdt, cdn) { 35 | frm.cscript.calculate_taxes_and_totals(); 36 | }, 37 | }); 38 | -------------------------------------------------------------------------------- /textile/overrides/sales_order_hooks.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | # from frappe import _ 3 | from erpnext.selling.doctype.sales_order.sales_order import SalesOrder 4 | from textile.fabric_printing.doctype.print_order.print_order import validate_transaction_against_print_order 5 | from textile.fabric_pretreatment.doctype.pretreatment_order.pretreatment_order import validate_transaction_against_pretreatment_order 6 | 7 | 8 | class SalesOrderDP(SalesOrder): 9 | def __init__(self, *args, **kwargs): 10 | super().__init__(*args, **kwargs) 11 | self.force_item_fields += ["fabric_item", "fabric_item_name", "textile_item_type"] 12 | 13 | def validate_with_previous_doc(self): 14 | super().validate_with_previous_doc() 15 | validate_transaction_against_pretreatment_order(self) 16 | validate_transaction_against_print_order(self) 17 | 18 | def update_previous_doc_status(self): 19 | super().update_previous_doc_status() 20 | 21 | pretreatment_orders = set([d.pretreatment_order for d in self.items if d.get('pretreatment_order')]) 22 | if not frappe.flags.skip_pretreatment_order_status_update: 23 | for name in pretreatment_orders: 24 | doc = frappe.get_doc("Pretreatment Order", name) 25 | doc.set_sales_order_status(update=True) 26 | doc.set_production_packing_status(update=True) 27 | doc.validate_ordered_qty(from_doctype=self.doctype) 28 | doc.set_status(update=True) 29 | doc.notify_update() 30 | 31 | print_orders = [] 32 | if not frappe.flags.skip_print_order_status_update: 33 | print_orders = set([d.print_order for d in self.items if d.get('print_order')]) 34 | print_order_row_names = [d.print_order_item for d in self.items if d.get('print_order_item')] 35 | 36 | for name in print_orders: 37 | doc = frappe.get_doc("Print Order", name) 38 | doc.set_sales_order_status(update=True) 39 | doc.set_production_packing_status(update=True) 40 | doc.validate_ordered_qty(from_doctype=self.doctype, row_names=print_order_row_names) 41 | doc.set_status(update=True) 42 | doc.notify_update() 43 | 44 | def update_status(self, status): 45 | super().update_status(status) 46 | 47 | pretreatment_orders = set([d.pretreatment_order for d in self.items if d.get('pretreatment_order')]) 48 | for name in pretreatment_orders: 49 | doc = frappe.get_doc("Pretreatment Order", name) 50 | doc.run_method("update_status", None) 51 | 52 | print_orders = set([d.print_order for d in self.items if d.get('print_order')]) 53 | for name in print_orders: 54 | doc = frappe.get_doc("Print Order", name) 55 | doc.run_method("update_status", None) 56 | 57 | def get_sales_order_item_bom(self, row): 58 | if row.get('pretreatment_order'): 59 | return frappe.db.get_value("Pretreatment Order", row.pretreatment_order, "ready_fabric_bom", cache=1) 60 | if row.get('print_order_item'): 61 | return frappe.db.get_value("Print Order Item", row.print_order_item, "design_bom", cache=1) 62 | 63 | return super().get_sales_order_item_bom(row) 64 | 65 | def get_skip_delivery_note(self, row): 66 | if row.get("pretreatment_order"): 67 | delivery_required = frappe.db.get_value("Pretreatment Order", row.pretreatment_order, "delivery_required", cache=1) 68 | if not delivery_required: 69 | return True 70 | 71 | return super().get_skip_delivery_note(row) 72 | 73 | 74 | def override_sales_order_dashboard(data): 75 | from textile.utils import override_sales_transaction_dashboard 76 | return override_sales_transaction_dashboard(data) 77 | 78 | 79 | def update_sales_order_mapper(mapper, target_doctype): 80 | if not mapper.get("Sales Order Item"): 81 | return 82 | 83 | field_map = mapper["Sales Order Item"]["field_map"] 84 | 85 | field_map["pretreatment_order"] = "pretreatment_order" 86 | 87 | field_map["print_order"] = "print_order" 88 | field_map["print_order_item"] = "print_order_item" 89 | 90 | 91 | def sales_order_autoname(doc, method): 92 | print_orders = set() 93 | pretreatment_orders = set() 94 | 95 | for d in doc.get("items"): 96 | if d.get("pretreatment_order"): 97 | pretreatment_orders.add(d.pretreatment_order) 98 | if d.get("print_order"): 99 | print_orders.add(d.print_order) 100 | 101 | name = None 102 | if len(print_orders) == 1: 103 | name = list(print_orders)[0] 104 | elif len(pretreatment_orders) == 1: 105 | name = list(pretreatment_orders)[0] 106 | 107 | if name and not frappe.db.exists("Sales Order", name): 108 | doc.name = name 109 | -------------------------------------------------------------------------------- /textile/overrides/stock_entry_hooks.js: -------------------------------------------------------------------------------- 1 | frappe.ui.form.on('Stock Entry', { 2 | refresh: function(frm) { 3 | if (frm.doc.docstatus === 0) { 4 | if (frappe.model.can_read("Print Order") || frappe.model.can_select("Print Order")) { 5 | frm.add_custom_button(__('Print Order Fabrics'), function () { 6 | frm.events.get_items_from_print_order(frm); 7 | }, __("Get Items From")); 8 | } 9 | } 10 | }, 11 | 12 | get_items_from_print_order(frm) { 13 | erpnext.utils.map_current_doc({ 14 | method: "textile.fabric_printing.doctype.print_order.print_order.make_customer_fabric_stock_entry", 15 | source_doctype: "Print Order", 16 | target: frm, 17 | setters: [ 18 | { 19 | fieldtype: 'Link', 20 | label: __('Customer'), 21 | options: 'Customer', 22 | fieldname: 'customer', 23 | default: frm.doc.customer || undefined, 24 | }, 25 | ], 26 | columns: ['customer_name', 'fabric_item_name', 'process_item_name', 'transaction_date'], 27 | get_query_filters: { 28 | docstatus: 1, 29 | status: ["!=", "Closed"], 30 | per_produced: ["<", 99.99], 31 | company: frm.doc.company, 32 | customer: frm.doc.customer || undefined, 33 | } 34 | }); 35 | } 36 | }); 37 | -------------------------------------------------------------------------------- /textile/overrides/taxes_and_totals_hooks.js: -------------------------------------------------------------------------------- 1 | frappe.provide("textile"); 2 | 3 | textile.calculate_panel_qty = function() { 4 | if ( 5 | !frappe.meta.has_field(this.frm.doc.doctype + " Item", 'panel_length_meter') 6 | || !frappe.meta.has_field(this.frm.doc.doctype + " Item", 'panel_qty') 7 | ) { 8 | return; 9 | } 10 | 11 | for (let row of this.frm.doc.items || []) { 12 | if (cint(row.panel_based_qty) && flt(row.panel_length_meter)) { 13 | row.panel_qty = flt(flt(row.stock_qty) / flt(row.panel_length_meter), precision("panel_qty", row)); 14 | } else { 15 | row.panel_qty = 0; 16 | } 17 | } 18 | } 19 | 20 | textile.calculate_panel_length_meter = function(frm, cdt, cdn) { 21 | let row = frappe.get_doc(cdt, cdn); 22 | 23 | if (row.panel_qty && row.panel_based_qty) { 24 | row.panel_length_meter = flt(row.stock_qty) / flt(row.panel_qty); 25 | } else { 26 | row.panel_length_meter = 0; 27 | } 28 | 29 | if (frm.doc.doctype == "Packing Slip") { 30 | frm.cscript.calculate_totals(); 31 | } else { 32 | frm.cscript.calculate_taxes_and_totals(); 33 | } 34 | } 35 | 36 | textile.set_printed_fabric_details = function () { 37 | if (!frappe.meta.has_field(this.frm.doc.doctype, "printed_fabrics")) { 38 | return; 39 | } 40 | 41 | const get_key = (obj) => cstr([obj.fabric_item, cint(obj.is_return_fabric)]); 42 | 43 | // Group fabrics and calculate totals 44 | let fabric_summary = {} 45 | for (let item of this.frm.doc.items) { 46 | if (!item.fabric_item || (item.textile_item_type != "Printed Design" && !item.is_return_fabric)) { 47 | continue; 48 | } 49 | 50 | let empty_row = { 51 | "fabric_item": item.fabric_item, 52 | "fabric_item_name": item.fabric_item_name + (item.is_return_fabric ? " (Return Fabric)" : ""), 53 | "fabric_qty": 0, 54 | "fabric_rate": 0, 55 | "fabric_amount": 0, 56 | "is_return_fabric": cint(item.is_return_fabric), 57 | } 58 | 59 | let key = get_key(item); 60 | let fabric_dict = fabric_summary[key]; 61 | if (!fabric_dict) { 62 | fabric_dict = fabric_summary[key] = Object.assign({}, empty_row); 63 | } 64 | 65 | fabric_dict.fabric_qty += flt(item.stock_qty); 66 | fabric_dict.fabric_amount += flt(item.amount); 67 | } 68 | 69 | // Calculate Rate 70 | for (let fabric_dict of Object.values(fabric_summary)) { 71 | let fabric_qty_df = frappe.meta.get_docfield("Printed Fabric Detail", "fabric_qty", this.frm.doc.name); 72 | let qty_precision = frappe.meta.get_field_precision(fabric_qty_df); 73 | fabric_dict.fabric_qty = flt(fabric_dict.fabric_qty, qty_precision); 74 | fabric_dict.fabric_rate = fabric_dict.fabric_qty ? fabric_dict.fabric_amount / fabric_dict.fabric_qty : 0; 75 | } 76 | 77 | // Update Rows 78 | const get_row = (fabric_item, is_return_fabric) => { 79 | let existing_rows = (this.frm.doc.printed_fabrics || []).filter((d) => { 80 | return ( 81 | d.fabric_item == fabric_item 82 | && cint(d.is_return_fabric) == cint(is_return_fabric) 83 | ) 84 | }); 85 | return existing_rows.length ? existing_rows[0] : null; 86 | } 87 | 88 | for (let fabric_dict of Object.values(fabric_summary)) { 89 | let row = get_row(fabric_dict.fabric_item, fabric_dict.is_return_fabric); 90 | if (!row) { 91 | row = this.frm.add_child("printed_fabrics"); 92 | } 93 | 94 | Object.assign(row, fabric_dict); 95 | } 96 | 97 | // Reset removed fabrics rows 98 | for (let printed_fabric_row of this.frm.doc.printed_fabrics || []) { 99 | let key = get_key(printed_fabric_row); 100 | if (!fabric_summary[key]) { 101 | printed_fabric_row.fabric_qty = 0; 102 | printed_fabric_row.fabric_rate = 0; 103 | printed_fabric_row.fabric_amount = 0; 104 | } 105 | } 106 | } 107 | 108 | textile.update_item_args_for_pricing = function (row, item_args) { 109 | item_args.pretreatment_order = row.pretreatment_order; 110 | item_args.print_order = row.print_order; 111 | } 112 | 113 | erpnext.taxes_and_totals_hooks.push(textile.calculate_panel_qty); 114 | erpnext.taxes_and_totals_hooks.push(textile.set_printed_fabric_details); 115 | 116 | erpnext.update_item_args_for_pricing_hooks.push(textile.update_item_args_for_pricing); 117 | -------------------------------------------------------------------------------- /textile/overrides/taxes_and_totals_hooks.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | from frappe.utils import cint, flt 3 | 4 | 5 | def calculate_taxes_and_totals(self): 6 | calculate_panel_qty(self.doc) 7 | set_printed_fabric_details(self.doc) 8 | 9 | 10 | def calculate_panel_qty(self): 11 | item_meta = frappe.get_meta(self.doctype + " Item") 12 | 13 | if not ( 14 | item_meta.has_field('panel_length_meter') and 15 | item_meta.has_field('panel_based_qty') and 16 | item_meta.has_field('panel_qty') 17 | ): 18 | return 19 | 20 | for row in self.items: 21 | if cint(row.panel_based_qty) and flt(row.panel_length_meter): 22 | row.panel_qty = flt(flt(row.stock_qty) / flt(row.panel_length_meter), row.precision("panel_qty")) 23 | else: 24 | row.panel_qty = 0 25 | 26 | 27 | def set_printed_fabric_details(self): 28 | if not self.meta.has_field("printed_fabrics"): 29 | return 30 | 31 | # Group fabrics and calculate totals 32 | fabric_summary = {} 33 | for item in self.items: 34 | if not item.fabric_item or (item.textile_item_type != "Printed Design" and not item.is_return_fabric): 35 | continue 36 | 37 | key = (item.fabric_item, cint(item.is_return_fabric)) 38 | fabric_dict = fabric_summary.setdefault(key, frappe._dict({ 39 | "fabric_item": item.fabric_item, 40 | "fabric_item_name": item.fabric_item_name + (" (Return Fabric)" if cint(item.is_return_fabric) else ""), 41 | "fabric_qty": 0, 42 | "fabric_rate": 0, 43 | "fabric_amount": 0, 44 | "is_return_fabric": cint(item.is_return_fabric), 45 | })) 46 | 47 | fabric_dict.fabric_qty += flt(item.stock_qty) 48 | fabric_dict.fabric_amount += flt(item.amount) 49 | 50 | # Calculate Rate 51 | for fabric_dict in fabric_summary.values(): 52 | fabric_dict.fabric_qty = flt(fabric_dict.fabric_qty, self.precision("fabric_qty", "printed_fabrics")) 53 | fabric_dict.fabric_rate = fabric_dict.fabric_amount / fabric_dict.fabric_qty if fabric_dict.fabric_qty else 0 54 | 55 | # Update rows 56 | def get_row(fabric_item, is_return_fabric): 57 | existing_rows = [d for d in self.printed_fabrics if d.fabric_item == fabric_item and cint(d.is_return_fabric) == is_return_fabric] 58 | return existing_rows[0] if existing_rows else None 59 | 60 | rows = [] 61 | for i, fabric_dict in enumerate(fabric_summary.values()): 62 | row = get_row(fabric_dict.fabric_item, cint(fabric_dict.is_return_fabric)) 63 | if not row: 64 | row = self.append("printed_fabrics") 65 | 66 | row.idx = i + 1 67 | row.update(fabric_dict) 68 | 69 | rows.append(row) 70 | 71 | self.printed_fabrics = rows 72 | -------------------------------------------------------------------------------- /textile/overrides/uom_hooks.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | from frappe import _ 3 | 4 | 5 | def on_uom_conversion_factor_update(doc, method): 6 | from textile.utils import update_conversion_factor_global_defaults 7 | 8 | uoms = [doc.from_uom, doc.to_uom] 9 | if "Meter" in uoms or "Yard" in uoms or "Inch" in uoms: 10 | update_conversion_factor_global_defaults() 11 | 12 | 13 | def before_uom_rename(doc, method, old, new, merge): 14 | if doc.name in ("Meter", "Yard", "Inch", "Square Meter"): 15 | frappe.throw(_("Not allowed to rename UOM {0}").format(doc.name)) 16 | -------------------------------------------------------------------------------- /textile/overrides/work_order_list_hooks.js: -------------------------------------------------------------------------------- 1 | frappe.listview_settings['Work Order'].original_onload = frappe.listview_settings['Work Order'].onload; 2 | frappe.listview_settings['Work Order'].onload = function(listview) { 3 | frappe.listview_settings['Work Order'].original_onload(listview); 4 | 5 | if (listview.page.fields_dict.fabric_item) { 6 | listview.page.fields_dict.fabric_item.get_query = () => { 7 | return erpnext.queries.item({ 8 | "textile_item_type": ["in", ["Ready Fabric", "Greige Fabric"]], 9 | "include_disabled": 1 10 | }); 11 | } 12 | } 13 | 14 | if (listview.page.fields_dict.process_item) { 15 | listview.page.fields_dict.process_item.get_query = () => { 16 | return erpnext.queries.item({"textile_item_type": "Print Process", "include_disabled": 1}); 17 | } 18 | } 19 | } 20 | 21 | frappe.listview_settings['Work Order'].add_fields_if_missing = function (fields) { 22 | for (let fieldname of fields) { 23 | if (!frappe.listview_settings['Work Order'].add_fields.includes(fieldname)) { 24 | frappe.listview_settings['Work Order'].add_fields.push(fieldname); 25 | } 26 | } 27 | } 28 | 29 | frappe.listview_settings['Work Order'].add_fields_if_missing([ 30 | "print_order", "pretreatment_order", 31 | "customer", "customer_name", 32 | "fabric_item", "fabric_item_name", 33 | "process_item", "process_item_name", 34 | ]); 35 | -------------------------------------------------------------------------------- /textile/patches.txt: -------------------------------------------------------------------------------- 1 | [pre_model_sync] 2 | textile.patches.reinstall_digital_printing #2-Mar #18-05-22 3 | textile.patches.update_conversion_factor_global_defaults # 27-06-22 4 | execute:frappe.delete_doc_if_exists("Custom Field", "Item-process_item") 5 | textile.patches.update_fabric_items_conversions 6 | textile.patches.set_work_order_packing_slip_required 7 | textile.patches.change_print_order_status_not_started 8 | textile.patches.refactor_fabric_printing 9 | textile.patches.set_is_sub_contracted #1 10 | textile.patches.set_printed_design_material_request_type 11 | textile.patches.delivery_status_not_applicable_for_not_started_orders 12 | textile.patches.set_line_fabric_item_details 13 | textile.patches.change_panel_sales_uom_to_meter 14 | textile.patches.unset_sales_uom_for_printed_design_items 15 | textile.patches.update_fabric_material_tariff_numbers 16 | textile.patches.update_stock_entry_types 17 | textile.patches.setup_textile_item_types 18 | execute:frappe.delete_doc_if_exists("Page", "work-order-packing") 19 | execute:frappe.delete_doc_if_exists("Custom Field", "Customer-printing_cb_2") 20 | textile.patches.set_line_textile_item_type 21 | textile.patches.rename_stock_entry_type_for_pretreatment_production 22 | textile.patches.enable_allow_process_loss 23 | 24 | [post_model_sync] 25 | textile.patches.set_panel_based_qty 26 | textile.patches.update_print_order_statuses 27 | textile.patches.update_print_order_item_creation_status 28 | textile.patches.remove_item_design_name_field 29 | textile.patches.set_work_order_fabric_details 30 | execute:frappe.delete_doc_if_exists("Page", "print-work-orders") 31 | textile.patches.update_print_order_production_packing_status 32 | textile.patches.set_work_order_process_details 33 | textile.patches.rename_textile_item_type 34 | textile.patches.update_is_return_fabric_field 35 | textile.patches.set_default_fabric_pickup 36 | textile.patches.rename_process_component_field 37 | textile.patches.set_do_not_explode_for_fabric 38 | textile.patches.set_fabric_warehouse 39 | textile.patches.delete_duplicate_file_attachments 40 | execute:frappe.delete_doc_if_exists("Report", "Print Packing List") 41 | textile.patches.set_print_order_internal_customer 42 | textile.patches.set_pretreatment_order_subcontractable_qty 43 | textile.patches.update_fabric_conversion_uoms 44 | textile.patches.set_return_fabric_skip_sales_invoice 45 | textile.patches.set_default_coating_cost_center 46 | textile.patches.fix_return_fabric_skip_sales_invoice 47 | textile.patches.set_coating_order_actual_end_date 48 | textile.patches.set_print_order_rejected_qty 49 | textile.patches.set_pretreatment_greige_fabric_batch_no -------------------------------------------------------------------------------- /textile/patches/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/patches/__init__.py -------------------------------------------------------------------------------- /textile/patches/change_panel_sales_uom_to_meter.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | 3 | 4 | def execute(): 5 | frappe.db.sql(""" 6 | update `tabItem` 7 | set sales_uom = 'Meter' 8 | where sales_uom = 'Panel' and textile_item_type = 'Printed Design' 9 | """) 10 | -------------------------------------------------------------------------------- /textile/patches/change_print_order_status_not_started.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | 3 | 4 | def execute(): 5 | frappe.reload_doctype("Print Order") 6 | frappe.db.sql(""" 7 | update `tabPrint Order` 8 | set status = 'Not Started' 9 | where status = 'To Confirm Order' 10 | """) 11 | -------------------------------------------------------------------------------- /textile/patches/delete_duplicate_file_attachments.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | 3 | 4 | def execute(): 5 | duplicates = frappe.db.sql(""" 6 | select file_url, attached_to_doctype, attached_to_name 7 | from `tabFile` 8 | where is_folder = 0 9 | and ifnull(attached_to_doctype) != '' 10 | and ifnull(attached_to_name) != '' 11 | group by file_url, attached_to_doctype, attached_to_name 12 | having count(*) > 1 13 | """, as_dict=1) 14 | 15 | if not duplicates: 16 | print("No Duplicate Attachments") 17 | return 18 | 19 | print("{0} distinct duplicate file attachments found".format(len(duplicates))) 20 | 21 | for dup in duplicates: 22 | files = frappe.get_all("File", filters=dup, fields="*") 23 | if len(files) <= 1: 24 | frappe.throw("Something wrong with the patch") 25 | 26 | to_keep = files[0].name 27 | for file in files: 28 | if file.get("rotated_image"): 29 | to_keep = file.name 30 | 31 | delete_filters = dup.copy() 32 | delete_filters["name"] = ["!=", to_keep] 33 | frappe.db.delete("File", filters=delete_filters) 34 | -------------------------------------------------------------------------------- /textile/patches/delivery_status_not_applicable_for_not_started_orders.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | 3 | 4 | def execute(): 5 | frappe.db.sql(""" 6 | update `tabPrint Order` 7 | set delivery_status = 'Not Applicable' 8 | where (status = 'Not Started' or docstatus = 0) 9 | """) 10 | 11 | frappe.db.sql(""" 12 | update `tabPretreatment Order` 13 | set delivery_status = 'Not Applicable' 14 | where (status = 'Not Started' or docstatus = 0) 15 | """) 16 | -------------------------------------------------------------------------------- /textile/patches/enable_allow_process_loss.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | 3 | 4 | def execute(): 5 | frappe.reload_doctype("Work Order") 6 | frappe.db.sql(""" 7 | update `tabWork Order` 8 | set allow_process_loss = 1, allow_material_consumption = 1 9 | where pretreatment_order != '' and pretreatment_order is not null 10 | """) 11 | -------------------------------------------------------------------------------- /textile/patches/fix_return_fabric_skip_sales_invoice.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | 3 | 4 | def execute(): 5 | dns = frappe.db.sql_list(""" 6 | select distinct i.parent 7 | from `tabDelivery Note Item` i 8 | inner join `tabDelivery Note` p on p.name = i.parent 9 | inner join `tabItem` item on item.name = i.item_code 10 | where p.docstatus = 1 11 | and i.skip_sales_invoice = 1 and item.is_customer_provided_item = 0 and i.is_return_fabric = 1 12 | """) 13 | 14 | for i, name in enumerate(dns): 15 | print(f"{i+1} / {len(dns)}: {name}") 16 | doc = frappe.get_doc("Delivery Note", name) 17 | doc.set_skip_sales_invoice(update=True, update_modified=True) 18 | doc.set_billing_status(update=True, update_modified=True) 19 | doc.set_status(update=True, update_modified=True) 20 | -------------------------------------------------------------------------------- /textile/patches/refactor_fabric_printing.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | 3 | 4 | def execute(): 5 | frappe.rename_doc("Module Def", "Digital Printing", "Fabric Printing", force=1) 6 | frappe.rename_doc("Workspace", "Digital Printing", "Fabric Printing", force=1) 7 | frappe.rename_doc("DocType", "Digital Printing Settings", "Fabric Printing Settings", force=1) -------------------------------------------------------------------------------- /textile/patches/reinstall_digital_printing.py: -------------------------------------------------------------------------------- 1 | from textile.install import after_install 2 | 3 | 4 | def execute(): 5 | after_install() 6 | -------------------------------------------------------------------------------- /textile/patches/remove_item_design_name_field.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | 3 | 4 | def execute(): 5 | transaction_dts = [ 6 | "Sales Order Item", "Delivery Note Item", "Sales Invoice Item", "Packing Slip Item", 7 | "BOM Item", "Stock Entry Detail" 8 | ] 9 | 10 | frappe.delete_doc_if_exists("Custom Field", "Item-design_name") 11 | 12 | frappe.db.sql(""" 13 | update `tabItem` 14 | set item_name = design_name 15 | where ifnull(design_name, '') != '' and textile_item_type = 'Printed Design' 16 | """) 17 | 18 | for dt in transaction_dts: 19 | frappe.db.sql(f""" 20 | update `tab{dt}` t 21 | inner join `tabItem` i on i.name = t.item_code 22 | set t.item_name = i.item_name 23 | where i.textile_item_type = 'Printed Design' 24 | """) 25 | 26 | frappe.db.sql(""" 27 | update `tabWork Order` t 28 | inner join `tabItem` i on i.name = t.production_item 29 | set t.item_name = i.item_name 30 | where i.textile_item_type = 'Printed Design' 31 | """) 32 | 33 | frappe.db.sql(""" 34 | update `tabBOM` t 35 | inner join `tabItem` i on i.name = t.item 36 | set t.item_name = i.item_name 37 | where i.textile_item_type = 'Printed Design' 38 | """) 39 | -------------------------------------------------------------------------------- /textile/patches/rename_process_component_field.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | from frappe.utils.fixtures import sync_fixtures 3 | from frappe.model.utils.rename_field import rename_field 4 | 5 | 6 | def execute(): 7 | frappe.delete_doc_if_exists("Custom Field", f"Item-print_process_component") 8 | 9 | sync_fixtures(app="textile") 10 | 11 | rename_field("Item", "print_process_component", "process_component") 12 | -------------------------------------------------------------------------------- /textile/patches/rename_stock_entry_type_for_pretreatment_production.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | from frappe.model.utils.rename_field import rename_field 3 | 4 | 5 | def execute(): 6 | frappe.reload_doc("fabric_pretreatment", "doctype", "fabric_pretreatment_settings") 7 | rename_field("Fabric Pretreatment Settings", 8 | "stock_entry_type_for_pretreatment_prodution", "stock_entry_type_for_pretreatment_production") 9 | -------------------------------------------------------------------------------- /textile/patches/rename_textile_item_type.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | from frappe.utils.fixtures import sync_fixtures 3 | from frappe.model.utils.rename_field import rename_field 4 | 5 | textile_item_type_dts = ["Item", "Item Group", "Item Source", "Brand"] 6 | 7 | 8 | def execute(): 9 | for dt in textile_item_type_dts: 10 | frappe.delete_doc_if_exists("Custom Field", f"{dt}-print_item_type") 11 | 12 | sync_fixtures(app="textile") 13 | 14 | for dt in textile_item_type_dts: 15 | rename_field(dt, "print_item_type", "textile_item_type") 16 | 17 | for dt in textile_item_type_dts: 18 | frappe.db.sql(f""" 19 | update `tab{dt}` 20 | set textile_item_type = 'Ready Fabric' 21 | where textile_item_type = 'Fabric' 22 | """) 23 | -------------------------------------------------------------------------------- /textile/patches/set_coating_order_actual_end_date.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | 3 | 4 | def execute(): 5 | names = frappe.get_all("Coating Order", filters={"docstatus": 1}) 6 | for name in names: 7 | doc = frappe.get_doc("Coating Order", name) 8 | doc.set_coating_status(update=False) 9 | doc.db_set("actual_end_date", doc.actual_end_date, update_modified=False) 10 | doc.clear_cache() 11 | -------------------------------------------------------------------------------- /textile/patches/set_default_coating_cost_center.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | 3 | 4 | def execute(): 5 | doc = frappe.get_single("Fabric Printing Settings") 6 | if doc.default_printing_cost_center: 7 | doc.default_coating_cost_center = doc.default_printing_cost_center 8 | doc.save(ignore_permissions=True) 9 | -------------------------------------------------------------------------------- /textile/patches/set_default_fabric_pickup.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | from frappe.utils.fixtures import sync_fixtures 3 | 4 | 5 | def execute(): 6 | sync_fixtures(app="textile") 7 | frappe.db.sql("update `tabItem` set fabric_per_pickup = 100") 8 | frappe.db.sql("update `tabPrint Order` set fabric_per_pickup = 100") 9 | -------------------------------------------------------------------------------- /textile/patches/set_do_not_explode_for_fabric.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | 3 | 4 | def execute(): 5 | frappe.db.sql(""" 6 | update `tabBOM Item` bom_i 7 | inner join `tabItem` item on item.name = bom_i.item_code 8 | set do_not_explode = 1 9 | where item.textile_item_type in ('Ready Fabric', 'Greige Fabric') 10 | """) 11 | -------------------------------------------------------------------------------- /textile/patches/set_fabric_warehouse.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | 3 | 4 | def execute(): 5 | frappe.db.sql(""" 6 | update `tabPrint Order` 7 | set fabric_warehouse = source_warehouse 8 | """) 9 | 10 | frappe.db.sql(""" 11 | update `tabPretreatment Order` 12 | set fabric_warehouse = source_warehouse 13 | """) 14 | 15 | printing_settings = frappe.get_single("Fabric Printing Settings") 16 | printing_settings.default_printing_fabric_warehouse = printing_settings.default_printing_source_warehouse 17 | printing_settings.save() 18 | 19 | pretreatment_settings = frappe.get_single("Fabric Pretreatment Settings") 20 | pretreatment_settings.default_pretreatment_fabric_warehouse = pretreatment_settings.default_pretreatment_source_warehouse 21 | pretreatment_settings.save() 22 | -------------------------------------------------------------------------------- /textile/patches/set_is_sub_contracted.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | 3 | 4 | def execute(): 5 | frappe.db.sql(""" 6 | update `tabItem` 7 | set is_sub_contracted_item = 0 8 | """) 9 | 10 | frappe.db.sql(""" 11 | update `tabItem` im 12 | inner join `tabPurchase Order Item` poi on poi.item_code = im.name 13 | inner join `tabPurchase Order` po on po.name = poi.parent 14 | set im.is_sub_contracted_item = 1 15 | where po.docstatus = 1 and po.is_subcontracted = 1 16 | """) 17 | -------------------------------------------------------------------------------- /textile/patches/set_line_fabric_item_details.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | from frappe.utils.fixtures import sync_fixtures 3 | 4 | 5 | def execute(): 6 | frappe.reload_doctype("Sales Order Item") 7 | frappe.reload_doctype("Delivery Note Item") 8 | frappe.reload_doctype("Sales Invoice Item") 9 | frappe.reload_doctype("Packing Slip Item") 10 | 11 | sync_fixtures(app="textile") 12 | 13 | dts = ["Sales Order Item", "Delivery Note Item", "Sales Invoice Item", "Packing Slip Item", "Stock Entry Detail"] 14 | for dt in dts: 15 | frappe.db.sql(f""" 16 | update `tab{dt}` line 17 | inner join `tabItem` im on im.name = line.item_code 18 | set 19 | line.fabric_item = im.fabric_item, 20 | line.fabric_item_name = im.fabric_item_name 21 | """) 22 | 23 | frappe.db.sql(f""" 24 | update `tab{dt}` line 25 | inner join `tabItem` im on im.name = line.item_code 26 | set 27 | line.fabric_item = line.item_code, 28 | line.fabric_item_name = im.item_name 29 | where im.textile_item_type in ('Greige Fabric', 'Ready Fabric') 30 | """) 31 | 32 | if frappe.get_meta(dt).has_field("print_order"): 33 | frappe.db.sql(f""" 34 | update `tab{dt}` line 35 | inner join `tabPrint Order` pro on pro.name = line.print_order 36 | set 37 | line.fabric_item = pro.fabric_item, 38 | line.fabric_item_name = pro.fabric_item_name 39 | """) 40 | 41 | if frappe.get_meta(dt).has_field("is_printed_fabric"): 42 | frappe.db.sql(f""" 43 | update `tab{dt}` line 44 | inner join `tabItem` im on im.name = line.item_code 45 | set line.is_printed_fabric = 1 46 | where im.textile_item_type = 'Printed Design' 47 | """) 48 | -------------------------------------------------------------------------------- /textile/patches/set_line_textile_item_type.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | from frappe.utils.fixtures import sync_fixtures 3 | 4 | 5 | def execute(): 6 | dts = ["Quotation Item", "Sales Order Item", "Delivery Note Item", "Sales Invoice Item"] 7 | 8 | for dt in dts: 9 | frappe.reload_doctype(dt) 10 | 11 | sync_fixtures(app="textile") 12 | 13 | for dt in dts: 14 | if frappe.get_meta(dt).has_field("textile_item_type"): 15 | frappe.db.sql(f""" 16 | update `tab{dt}` line 17 | inner join `tabItem` im on im.name = line.item_code 18 | set 19 | line.textile_item_type = im.textile_item_type 20 | """) 21 | 22 | frappe.delete_doc_if_exists("Custom Field", f"{dt}-is_printed_fabric") 23 | -------------------------------------------------------------------------------- /textile/patches/set_panel_based_qty.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | from frappe.model.utils.rename_field import rename_field 3 | from frappe.utils.fixtures import sync_fixtures 4 | 5 | 6 | def execute(): 7 | sync_fixtures(app="textile") 8 | 9 | doctypes = ["Sales Order Item", "Delivery Note Item", "Sales Invoice Item"] 10 | 11 | for dt in doctypes: 12 | frappe.delete_doc_if_exists("Custom Field", f"{dt}-show_panel_in_print") 13 | 14 | if frappe.db.has_column(dt, 'show_panel_in_print'): 15 | rename_field(dt, "show_panel_in_print", "panel_based_qty") 16 | 17 | for name in frappe.get_all("Print Order", pluck="name"): 18 | doc = frappe.get_doc("Print Order", name) 19 | doc.calculate_totals() 20 | for d in doc.items: 21 | d.db_set("panel_based_qty", d.panel_based_qty, update_modified=False) 22 | -------------------------------------------------------------------------------- /textile/patches/set_pretreatment_greige_fabric_batch_no.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | 3 | 4 | def execute(): 5 | frappe.db.sql(""" 6 | update `tabWork Order` 7 | set auto_select_batches_in_stock_entry = 1 8 | where print_order is not null and print_order != '' 9 | """) 10 | 11 | frappe.db.sql(""" 12 | update `tabPretreatment Order` o 13 | inner join `tabItem` i on i.name = o.greige_fabric_item 14 | set o.greige_fabric_has_batch_no = i.has_batch_no 15 | """) 16 | 17 | batch_orders = frappe.get_all("Pretreatment Order", filters={ 18 | "greige_fabric_has_batch_no": 1, "docstatus": 1, "production_status": "Produced" 19 | }, pluck="name") 20 | 21 | for pto_name in batch_orders: 22 | work_orders = frappe.get_all("Work Order", filters={"pretreatment_order": pto_name}, pluck="name") 23 | if not work_orders: 24 | continue 25 | 26 | pretreatment_order = frappe.get_doc("Pretreatment Order", pto_name) 27 | 28 | batch_nos = frappe.db.sql_list(""" 29 | select distinct i.batch_no 30 | from `tabStock Entry Detail` i 31 | inner join `tabStock Entry` ste on ste.name = i.parent 32 | where ste.docstatus = 1 33 | and ste.purpose = 'Manufacture' 34 | and ste.work_order in %s 35 | and i.item_code = %s 36 | and ifnull(i.s_warehouse, '') != '' 37 | and ifnull(i.t_warehouse, '') = '' 38 | """, [work_orders, pretreatment_order.greige_fabric_item]) 39 | 40 | if len(batch_nos) == 1: 41 | pretreatment_order.db_set("greige_fabric_batch_no", batch_nos[0], update_modified=False) 42 | pretreatment_order.update_work_order_greige_fabric_batch_no() 43 | -------------------------------------------------------------------------------- /textile/patches/set_pretreatment_order_subcontractable_qty.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | 3 | 4 | def execute(): 5 | names = frappe.get_all("Pretreatment Order", {"docstatus": 1}, pluck="name") 6 | for name in names: 7 | doc = frappe.get_doc("Pretreatment Order", name) 8 | doc.set_production_packing_status(update=True, update_modified=False) 9 | -------------------------------------------------------------------------------- /textile/patches/set_print_order_internal_customer.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | 3 | 4 | def execute(): 5 | internal_customers = frappe.get_all("Customer", {"is_internal_customer": 1}, pluck="name") 6 | if not internal_customers: 7 | return 8 | 9 | print_orders = frappe.get_all("Print Order", {"customer": ["in", internal_customers]}, pluck="name") 10 | for name in print_orders: 11 | doc = frappe.get_doc("Print Order", name) 12 | print(f"Updating Print Order {name} (Customer {doc.customer}) Internal Customer") 13 | doc.validate_is_internal_customer() 14 | doc.db_set({ 15 | "is_internal_customer": doc.is_internal_customer, 16 | "is_fabric_provided_by_customer": doc.is_fabric_provided_by_customer, 17 | }, update_modified=False) 18 | -------------------------------------------------------------------------------- /textile/patches/set_print_order_rejected_qty.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | 3 | 4 | def execute(): 5 | print_orders = frappe.db.sql_list(""" 6 | select distinct print_order 7 | from `tabPacking Slip Item` 8 | where print_order is not null and print_order != '' and rejected_qty != 0 and docstatus = 1 9 | """) 10 | 11 | for name in print_orders: 12 | doc = frappe.get_doc("Print Order", name) 13 | doc.set_production_packing_status(update=True, update_modified=False) 14 | doc.set_status(update=True, update_modified=False) 15 | -------------------------------------------------------------------------------- /textile/patches/set_printed_design_material_request_type.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | 3 | 4 | def execute(): 5 | frappe.db.sql(""" 6 | update `tabItem` 7 | set default_material_request_type = 'Manufacture' 8 | where textile_item_type = 'Printed Design' 9 | """) 10 | -------------------------------------------------------------------------------- /textile/patches/set_return_fabric_skip_sales_invoice.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | 3 | 4 | def execute(): 5 | frappe.db.sql(""" 6 | update `tabDelivery Note Item` i 7 | inner join `tabItem` item on item.name = i.item_code 8 | set i.skip_sales_invoice = 1 9 | where i.is_return_fabric = 1 and item.is_customer_provided_item = 1 and i.billed_qty = 0 10 | """) 11 | 12 | dns = frappe.db.sql_list(""" 13 | select distinct i.parent 14 | from `tabDelivery Note Item` i 15 | inner join `tabDelivery Note` p on p.name = i.parent 16 | inner join `tabItem` item on item.name = i.item_code 17 | where p.docstatus = 1 and i.is_return_fabric = 1 and item.is_customer_provided_item = 1 and i.billed_qty = 0 18 | """) 19 | 20 | for i, name in enumerate(dns): 21 | print(f"{i+1} / {len(dns)}: {name}") 22 | doc = frappe.get_doc("Delivery Note", name) 23 | doc.set_skip_sales_invoice_for_delivery_note(update=True, update_modified=False) 24 | doc.set_billing_status(update=True, update_modified=False) 25 | doc.set_status(update=True, update_modified=False) 26 | -------------------------------------------------------------------------------- /textile/patches/set_work_order_fabric_details.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | from frappe.utils.fixtures import sync_fixtures 3 | 4 | 5 | def execute(): 6 | sync_fixtures(app="textile") 7 | frappe.db.sql(""" 8 | update `tabWork Order` wo 9 | inner join `tabPrint Order` pro on pro.name = wo.print_order 10 | set 11 | wo.fabric_item = pro.fabric_item, 12 | wo.fabric_item_name = pro.fabric_item_name, 13 | wo.fabric_material = pro.fabric_material, 14 | wo.fabric_width = pro.fabric_width, 15 | wo.fabric_gsm = pro.fabric_gsm 16 | """) 17 | -------------------------------------------------------------------------------- /textile/patches/set_work_order_packing_slip_required.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | 3 | 4 | def execute(): 5 | frappe.reload_doctype("Work Order") 6 | frappe.reload_doctype("Packing Slip Item") 7 | 8 | frappe.db.sql(""" 9 | update `tabWork Order` wo 10 | inner join `tabPrint Order` pro on pro.name = wo.print_order 11 | set wo.packing_slip_required = pro.packing_slip_required 12 | """) 13 | 14 | frappe.db.sql(""" 15 | update `tabPacking Slip Item` psi 16 | inner join `tabWork Order` wo on wo.sales_order_item = psi.sales_order_item 17 | set psi.work_order = wo.name 18 | where wo.packing_slip_required = 1 19 | """) 20 | -------------------------------------------------------------------------------- /textile/patches/set_work_order_process_details.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | from frappe.utils.fixtures import sync_fixtures 3 | 4 | 5 | def execute(): 6 | sync_fixtures(app="textile") 7 | frappe.db.sql(""" 8 | update `tabWork Order` wo 9 | inner join `tabPrint Order` pro on pro.name = wo.print_order 10 | set 11 | wo.process_item = pro.process_item, 12 | wo.process_item_name = pro.process_item_name 13 | """) 14 | -------------------------------------------------------------------------------- /textile/patches/setup_textile_item_types.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | from textile.install import populate_textile_item_types 3 | 4 | 5 | def execute(): 6 | frappe.reload_doc("textile", "doctype", "textile_item_type") 7 | populate_textile_item_types() 8 | -------------------------------------------------------------------------------- /textile/patches/unset_sales_uom_for_printed_design_items.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | 3 | 4 | def execute(): 5 | frappe.db.sql(""" 6 | update `tabItem` 7 | set sales_uom = null 8 | where textile_item_type = 'Printed Design' 9 | """) 10 | -------------------------------------------------------------------------------- /textile/patches/update_conversion_factor_global_defaults.py: -------------------------------------------------------------------------------- 1 | def execute(): 2 | from textile.utils import update_conversion_factor_global_defaults 3 | update_conversion_factor_global_defaults() 4 | -------------------------------------------------------------------------------- /textile/patches/update_fabric_conversion_uoms.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | 3 | 4 | def execute(): 5 | item_codes = frappe.get_all("Item", filters={ 6 | "textile_item_type": ["in", ["Printed Design", "Ready Fabric", "Greige Fabric"]] 7 | }, pluck="name") 8 | 9 | for name in item_codes: 10 | doc = frappe.get_doc("Item", name) 11 | doc.set_fabric_conversion_uoms() 12 | doc.calculate_uom_conversion_factors() 13 | doc.update_child_table("uom_conversion_graph") 14 | doc.update_child_table("uoms") 15 | -------------------------------------------------------------------------------- /textile/patches/update_fabric_items_conversions.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | 3 | 4 | def execute(): 5 | item_codes = frappe.get_all("Item", filters={ 6 | "textile_item_type": ["in", ["Fabric", "Ready Fabric", "Greige Fabric", "Printed Design"]] 7 | }, pluck="name") 8 | 9 | for item_code in item_codes: 10 | doc = frappe.get_doc("Item", item_code) 11 | doc.run_method("validate_fabric_uoms") 12 | doc.calculate_uom_conversion_factors() 13 | doc.db_update() 14 | 15 | doc.update_child_table("uoms") 16 | doc.update_child_table("uom_conversion_graph") 17 | -------------------------------------------------------------------------------- /textile/patches/update_fabric_material_tariff_numbers.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | from textile.install import populate_customs_tariff_number, populate_fabric_material 3 | from textile.textile.doctype.fabric_material.fabric_material import update_item_tariff_numbers 4 | 5 | 6 | def execute(): 7 | frappe.reload_doc("textile", "doctype", "fabric_tariff_number") 8 | frappe.reload_doc("textile", "doctype", "fabric_material") 9 | frappe.reload_doc("stock", "doctype", "customs_tariff_number") 10 | 11 | populate_customs_tariff_number() 12 | populate_fabric_material(overwrite=True) 13 | 14 | for fabric_material in frappe.get_all("Fabric Material", pluck="name"): 15 | update_item_tariff_numbers(fabric_material) 16 | -------------------------------------------------------------------------------- /textile/patches/update_is_return_fabric_field.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | from frappe.utils.fixtures import sync_fixtures 3 | 4 | 5 | def execute(): 6 | sync_fixtures(app="textile") 7 | 8 | for doctype in ("Packing Slip", "Delivery Note", "Sales Invoice"): 9 | frappe.db.sql(""" 10 | UPDATE `tab{doctype} Item` i 11 | INNER JOIN `tabPrint Order` pro ON pro.name = i.print_order 12 | SET 13 | i.is_return_fabric = IF(i.item_code = pro.fabric_item, 1, 0) 14 | """.format(doctype=doctype)) 15 | -------------------------------------------------------------------------------- /textile/patches/update_print_order_item_creation_status.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | 3 | 4 | def execute(): 5 | print_orders = frappe.get_all("Print Order", pluck="name") 6 | for name in print_orders: 7 | doc = frappe.get_doc("Print Order", name) 8 | doc.set_item_creation_status(update=True, update_modified=False) 9 | doc.set_status(update=True, update_modified=False) 10 | 11 | doc.clear_cache() 12 | -------------------------------------------------------------------------------- /textile/patches/update_print_order_production_packing_status.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | 3 | 4 | def execute(): 5 | print_orders = frappe.get_all("Print Order", pluck="name") 6 | for name in print_orders: 7 | doc = frappe.get_doc("Print Order", name) 8 | doc.set_production_packing_status(update=True, update_modified=False) 9 | doc.set_status(update=True, update_modified=False) 10 | 11 | doc.clear_cache() 12 | -------------------------------------------------------------------------------- /textile/patches/update_print_order_statuses.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | 3 | 4 | def execute(): 5 | print_orders = frappe.get_all("Print Order", pluck="name") 6 | for name in print_orders: 7 | doc = frappe.get_doc("Print Order", name) 8 | doc.set_sales_order_status(update=True, update_modified=False) 9 | doc.set_production_packing_status(update=True, update_modified=False) 10 | doc.set_delivery_status(update=True, update_modified=False) 11 | doc.set_billing_status(update=True, update_modified=False) 12 | doc.set_status(update=True, update_modified=False) 13 | 14 | doc.clear_cache() 15 | -------------------------------------------------------------------------------- /textile/patches/update_stock_entry_types.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | from textile.install import populate_stock_entry_types 3 | 4 | 5 | def execute(): 6 | populate_stock_entry_types() 7 | -------------------------------------------------------------------------------- /textile/public/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/public/.gitkeep -------------------------------------------------------------------------------- /textile/public/js/textile_order.js: -------------------------------------------------------------------------------- 1 | frappe.provide("textile"); 2 | 3 | textile.TextileOrder = class TextileOrder extends frappe.ui.form.Controller { 4 | setup() { 5 | this.setup_queries(); 6 | } 7 | 8 | refresh() { 9 | erpnext.toggle_naming_series(); 10 | erpnext.hide_company(); 11 | } 12 | 13 | setup_queries() { 14 | this.frm.set_query('customer', erpnext.queries.customer); 15 | 16 | for (let warehouse_field of ["fabric_warehouse", "source_warehouse", "wip_warehouse", "fg_warehouse"]) { 17 | this.frm.set_query(warehouse_field, () => { 18 | return erpnext.queries.warehouse(this.frm.doc); 19 | }); 20 | } 21 | 22 | this.frm.set_query('cost_center', () => { 23 | return { 24 | filters: { 25 | "company": this.frm.doc.company, 26 | "is_group": 0 27 | } 28 | }; 29 | }); 30 | } 31 | 32 | get_is_internal_customer() { 33 | if (!this.frm.doc.customer || !this.frm.doc.company) { 34 | return this.frm.set_value("is_internal_customer", 0); 35 | } else { 36 | return frappe.call({ 37 | method: "textile.utils.is_internal_customer", 38 | args: { 39 | customer: this.frm.doc.customer, 40 | company: this.frm.doc.company, 41 | }, 42 | callback: (r) => { 43 | return this.frm.set_value("is_internal_customer", r.message); 44 | } 45 | }); 46 | } 47 | } 48 | 49 | get_fabric_stock_qty(prefix) { 50 | let fabric_field = cstr(prefix) + "fabric_item"; 51 | let qty_field = cstr(prefix) + "fabric_stock_qty"; 52 | 53 | if (this.frm.doc[fabric_field] && this.frm.doc.fabric_warehouse) { 54 | return this.frm.call({ 55 | method: "erpnext.stock.get_item_details.get_bin_details", 56 | args: { 57 | item_code: this.frm.doc[fabric_field], 58 | warehouse: this.frm.doc.fabric_warehouse, 59 | }, 60 | callback: (r) => { 61 | if (r.message) { 62 | this.frm.set_value(qty_field, flt(r.message.actual_qty)); 63 | } 64 | } 65 | }); 66 | } else { 67 | this.frm.set_value(qty_field, 0); 68 | } 69 | } 70 | 71 | set_items_delivery_date() { 72 | for (let d of this.frm.doc.items || []) { 73 | d.delivery_date = this.frm.doc.delivery_date; 74 | refresh_field("delivery_date", d.name, "items"); 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /textile/public/js/utils.js: -------------------------------------------------------------------------------- 1 | frappe.provide("textile"); 2 | 3 | textile.printing_components = { 4 | "coating_item": "Coating", 5 | "softener_item": "Softener", 6 | "sublimation_paper_item": "Sublimation Paper", 7 | "protection_paper_item": "Protection Paper", 8 | } 9 | 10 | textile.pretreatment_components = { 11 | "singeing_item": "Singeing", 12 | "desizing_item": "Desizing", 13 | "bleaching_item": "Bleaching", 14 | } 15 | 16 | textile.process_components = Object.assign({}, textile.printing_components, textile.pretreatment_components); 17 | 18 | $.extend(textile, { 19 | get_items_from_print_order: function (frm, method, filters, query) { 20 | let query_filters = { 21 | docstatus: 1, 22 | status: ["!=", "Closed"], 23 | items_created: 1, 24 | company: frm.doc.company, 25 | customer: frm.doc.customer || undefined, 26 | } 27 | if (filters) { 28 | Object.assign(query_filters, filters); 29 | } 30 | 31 | erpnext.utils.map_current_doc({ 32 | method: method, 33 | source_doctype: "Print Order", 34 | target: frm, 35 | setters: [ 36 | { 37 | fieldtype: 'Link', 38 | label: __('Customer'), 39 | options: 'Customer', 40 | fieldname: 'customer', 41 | default: frm.doc.customer || undefined, 42 | }, 43 | { 44 | fieldtype: 'Link', 45 | label: __('Fabric Item'), 46 | options: 'Item', 47 | fieldname: 'fabric_item', 48 | get_query: () => { 49 | return erpnext.queries.item({ textile_item_type: 'Ready Fabric' }); 50 | }, 51 | }, 52 | { 53 | fieldtype: 'Link', 54 | label: __('Process Item'), 55 | options: 'Item', 56 | fieldname: 'process_item', 57 | get_query: () => { 58 | return erpnext.queries.item({ textile_item_type: 'Print Process' }); 59 | }, 60 | }, 61 | ], 62 | columns: ['customer_name', 'fabric_item_name', 'process_item_name', 'transaction_date'], 63 | get_query: () => { 64 | return { 65 | query: query, 66 | filters: query_filters, 67 | } 68 | }, 69 | }); 70 | }, 71 | 72 | get_items_from_pretreatment_order: function (frm, method, filters, query) { 73 | let query_filters = { 74 | docstatus: 1, 75 | status: ["!=", "Closed"], 76 | company: frm.doc.company, 77 | customer: frm.doc.customer || undefined, 78 | } 79 | if (filters) { 80 | Object.assign(query_filters, filters); 81 | } 82 | 83 | erpnext.utils.map_current_doc({ 84 | method: method, 85 | source_doctype: "Pretreatment Order", 86 | target: frm, 87 | setters: [ 88 | { 89 | fieldtype: 'Link', 90 | label: __('Customer'), 91 | options: 'Customer', 92 | fieldname: 'customer', 93 | default: frm.doc.customer || undefined, 94 | }, 95 | { 96 | fieldtype: 'Link', 97 | label: __('Greige Fabric Item'), 98 | options: 'Item', 99 | fieldname: 'greige_fabric_item', 100 | get_query: () => { 101 | return erpnext.queries.item({ textile_item_type: 'Greige Fabric' }); 102 | }, 103 | }, 104 | { 105 | fieldtype: 'Link', 106 | label: __('Ready Fabric Item'), 107 | options: 'Item', 108 | fieldname: 'ready_fabric_item', 109 | get_query: () => { 110 | return erpnext.queries.item({ textile_item_type: 'Ready Fabric' }); 111 | }, 112 | }, 113 | ], 114 | columns: ['customer_name', 'greige_fabric_item_name', 'ready_fabric_item_name', 'transaction_date'], 115 | get_query: () => { 116 | return { 117 | query: query, 118 | filters: query_filters, 119 | } 120 | }, 121 | }); 122 | }, 123 | 124 | get_textile_conversion_factors: function () { 125 | return { 126 | inch_to_meter: flt(frappe.defaults.get_global_default("inch_to_meter")) || 0.0254, 127 | yard_to_meter: flt(frappe.defaults.get_global_default("yard_to_meter")) || 0.9144, 128 | meter_to_meter: 1 129 | } 130 | } 131 | }); 132 | -------------------------------------------------------------------------------- /textile/public/scss/print_list_view.scss: -------------------------------------------------------------------------------- 1 | .print-list-view-row { 2 | .list-row { 3 | height: auto; 4 | padding: 10px 15px; 5 | } 6 | 7 | .design-details { 8 | width: 65%; 9 | 10 | .design-name { 11 | font-size: 16px; 12 | } 13 | 14 | .progress { 15 | margin-top: 5px; 16 | } 17 | 18 | .design-properties table th { 19 | padding-right: 4px; 20 | } 21 | } 22 | 23 | .design-image { 24 | width: 35%; 25 | padding-left: 15px; 26 | 27 | img { 28 | max-height: 125px; 29 | } 30 | } 31 | 32 | .indicator-pill { 33 | padding: 15px 10px; 34 | } 35 | 36 | button { 37 | min-width: 70px; 38 | } 39 | } -------------------------------------------------------------------------------- /textile/public/scss/print_order_item_row.scss: -------------------------------------------------------------------------------- 1 | [data-fieldtype="Table"][data-fieldname="items"] .grid-field { 2 | .design-details { 3 | padding: 0; 4 | 5 | .reqd:after { 6 | content: ' *'; 7 | color: var(--red-400); 8 | } 9 | 10 | table { 11 | width: 100%; 12 | margin: 0; 13 | border: 0; 14 | 15 | thead td { 16 | padding: 0; 17 | border: 0; 18 | } 19 | 20 | th { 21 | font-size: var(--text-sm); 22 | background-color: var(--gray-100); 23 | overflow: hidden; 24 | text-overflow: ellipsis; 25 | white-space: nowrap; 26 | } 27 | 28 | th, .formatted-value { 29 | padding: 5px 7px; 30 | } 31 | td { 32 | padding: 0; 33 | font-size: var(--text-md); 34 | font-weight: 500; 35 | } 36 | 37 | tr:first-child { 38 | td, th { 39 | border-top: 0; 40 | } 41 | } 42 | tr:last-child { 43 | td, th { 44 | border-bottom: 0; 45 | } 46 | } 47 | tr { 48 | td:first-child, th:first-child { 49 | border-left: 0; 50 | } 51 | td:last-child, th:last-child { 52 | border-right: 0; 53 | } 54 | } 55 | } 56 | 57 | .form-control { 58 | padding: 5px 7px; 59 | border-radius: 0; 60 | border: 0; 61 | height: auto; 62 | font-size: var(--text-md); 63 | background-color: var(--gray-50); 64 | font-weight: 500; 65 | } 66 | .form-control.bold { 67 | font-weight: inherit; 68 | background-color: var(--yellow-50); 69 | } 70 | textarea.form-control { 71 | height: 28px !important; 72 | } 73 | 74 | .select-icon { 75 | top: 3px; 76 | right: 2px; 77 | } 78 | } 79 | 80 | .design-image { 81 | padding: 5px; 82 | img { 83 | max-height: 108px; 84 | } 85 | } 86 | } 87 | 88 | [data-theme="dark"] { 89 | [data-fieldtype="Table"][data-fieldname="items"] .grid-field { 90 | .design-details { 91 | table th { 92 | background-color: var(--gray-900); 93 | } 94 | } 95 | 96 | .form-control { 97 | background-color: var(--gray-700); 98 | } 99 | 100 | .form-control.bold { 101 | background-color: #1b0e00; 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /textile/public/scss/textile.bundle.scss: -------------------------------------------------------------------------------- 1 | @import "./print_list_view"; 2 | @import "./print_order_item_row"; -------------------------------------------------------------------------------- /textile/public/textile.bundle.js: -------------------------------------------------------------------------------- 1 | import "./js/utils.js" 2 | import "./js/textile_order.js" 3 | import "./js/print_list_view.js" 4 | import "./js/check_pricing.js" 5 | import "../overrides/taxes_and_totals_hooks.js" 6 | import "../overrides/work_order_hooks.js" 7 | import "../templates/print_order_item_row.html" -------------------------------------------------------------------------------- /textile/rotated_image.py: -------------------------------------------------------------------------------- 1 | import frappe 2 | from frappe import _ 3 | from frappe.utils import cint 4 | from frappe.core.doctype.file.utils import get_local_image 5 | from frappe.utils.user import is_website_user 6 | from frappe.core.doctype.file.utils import delete_file 7 | from werkzeug.utils import send_file 8 | import io 9 | import os 10 | import mimetypes 11 | 12 | 13 | @frappe.whitelist() 14 | def get_rotated_image(file, get_path=False): 15 | if not file: 16 | frappe.throw(_("File URL not provided")) 17 | 18 | file_id = get_file_id(file) 19 | if not file_id: 20 | raise frappe.DoesNotExistError 21 | 22 | file_doc = frappe.get_doc("File", file_id) 23 | if file_doc.is_private and is_website_user(): 24 | file_doc.raise_no_permission_to("read") 25 | 26 | rotated_image_url = get_rotated_image_url(file) 27 | 28 | if rotated_image_url and os.path.isfile(get_file_path(rotated_image_url)): 29 | rotated_file_path = get_file_path(rotated_image_url) 30 | rotated_filename = os.path.basename(rotated_file_path) 31 | output = open(rotated_file_path, "rb") 32 | else: 33 | rotated_filename, rotated_image_url, output = save_rotated_image_file(file, file_doc) 34 | 35 | if cint(get_path): 36 | return rotated_image_url 37 | else: 38 | return send_file( 39 | output, 40 | environ=frappe.local.request.environ, 41 | mimetype=mimetypes.guess_type(rotated_filename)[0] or "image/jpeg", 42 | download_name=rotated_filename, 43 | ) 44 | 45 | 46 | def get_file_id(file_url): 47 | files = frappe.db.sql(""" 48 | select name, file_url 49 | from `tabFile` 50 | where file_url = %s 51 | order by if(attached_to_doctype = 'Print Order', 0, 1), creation 52 | """, file_url, as_dict=1) 53 | 54 | file_id = None 55 | for d in files: 56 | if d.file_url == file_url: 57 | file_id = d.name 58 | break 59 | 60 | return file_id 61 | 62 | 63 | def get_rotated_image_url(file_url): 64 | files = frappe.get_all("File", filters={ 65 | "file_url": file_url, "rotated_image": ["is", "set"] 66 | }, fields=["file_url", "rotated_image"]) 67 | 68 | rotated_image_url = None 69 | for d in files: 70 | if d.file_url == file_url: 71 | rotated_image_url = d.rotated_image 72 | break 73 | 74 | return rotated_image_url 75 | 76 | 77 | def save_rotated_image_file(file, file_doc): 78 | rotated_filename, output = make_rotated_image(file) 79 | 80 | path = os.path.abspath(frappe.get_site_path( 81 | "private" if file_doc.is_private else "public", 82 | "files", 83 | rotated_filename.lstrip("/")) 84 | ) 85 | 86 | with open(path, "wb") as f: 87 | f.write(output.getbuffer()) 88 | output.seek(0) 89 | 90 | if file_doc.is_private: 91 | rotated_image_url = "/private/files/" + rotated_filename 92 | else: 93 | rotated_image_url = "/files/" + rotated_filename 94 | 95 | file_doc.db_set("rotated_image", rotated_image_url) 96 | frappe.db.commit() 97 | 98 | return rotated_filename, rotated_image_url, output 99 | 100 | 101 | def make_rotated_image(file): 102 | angle = 90 103 | view_height = 150 104 | 105 | original_image, original_filename, ext = get_local_image(file) 106 | image_format = original_image.format 107 | 108 | if original_image.mode in ("RGBA", "CMYK"): 109 | original_image = original_image.convert("RGB") 110 | 111 | scaling_factor = view_height / original_image.width 112 | width = original_image.height * scaling_factor 113 | 114 | height = cint(view_height * 2) 115 | width = cint(width * 2) 116 | 117 | original_image.thumbnail((height, width)) 118 | 119 | modified_image = original_image.rotate(angle, expand=True) 120 | 121 | rotated_filename = original_filename.split("/")[-1] 122 | rotated_filename = f"{rotated_filename}_rotated.{ext}" 123 | 124 | output = io.BytesIO() 125 | modified_image.save( 126 | output, 127 | format=image_format or "jpeg", 128 | quality=70, 129 | ) 130 | output.seek(0) 131 | 132 | return rotated_filename, output 133 | 134 | 135 | def get_file_path(file_url): 136 | if file_url.startswith("/private"): 137 | file_url_path = (file_url.lstrip("/"),) 138 | else: 139 | file_url_path = ("public", file_url.lstrip("/")) 140 | 141 | file_path = frappe.get_site_path(*file_url_path) 142 | return file_path 143 | 144 | 145 | def delete_file_data_content(doc, only_thumbnail=False): 146 | doc.delete_file_from_filesystem(only_thumbnail=only_thumbnail) 147 | if doc.rotated_image: 148 | delete_file(doc.rotated_image) 149 | -------------------------------------------------------------------------------- /textile/templates/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/templates/__init__.py -------------------------------------------------------------------------------- /textile/templates/pages/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/templates/pages/__init__.py -------------------------------------------------------------------------------- /textile/templates/print_order_item_row.html: -------------------------------------------------------------------------------- 1 |
2 | {% if (doc) { %} 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 16 | 20 | 24 | 28 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 47 | 50 | 53 | 56 | 59 | 62 | 65 | 66 | 67 | {% } else { %} 68 | {%= __("Design Details") %} 69 | {% } %} 70 |
71 | 72 |
73 | {% if (doc) { %} 74 | 75 | {% } else { %} 76 | {%= __("Design Image") %} 77 | {% } %} 78 |
79 | -------------------------------------------------------------------------------- /textile/textile/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/textile/__init__.py -------------------------------------------------------------------------------- /textile/textile/doctype/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/textile/doctype/__init__.py -------------------------------------------------------------------------------- /textile/textile/doctype/fabric_material/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/textile/doctype/fabric_material/__init__.py -------------------------------------------------------------------------------- /textile/textile/doctype/fabric_material/fabric_material.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, ParaLogic and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('Fabric Material', { 5 | // refresh: function(frm) { 6 | 7 | // } 8 | }); 9 | -------------------------------------------------------------------------------- /textile/textile/doctype/fabric_material/fabric_material.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "allow_rename": 1, 4 | "autoname": "field:fabric_material", 5 | "creation": "2023-02-08 17:03:01.630993", 6 | "default_view": "List", 7 | "doctype": "DocType", 8 | "editable_grid": 1, 9 | "engine": "InnoDB", 10 | "field_order": [ 11 | "fabric_material", 12 | "abbreviation", 13 | "customs_tariff_number_section", 14 | "greige_fabric_tariff", 15 | "ready_fabric_tariff", 16 | "printed_fabric_tariff" 17 | ], 18 | "fields": [ 19 | { 20 | "fieldname": "fabric_material", 21 | "fieldtype": "Data", 22 | "label": "Fabric Material", 23 | "reqd": 1, 24 | "unique": 1 25 | }, 26 | { 27 | "allow_in_quick_entry": 1, 28 | "fieldname": "abbreviation", 29 | "fieldtype": "Data", 30 | "in_list_view": 1, 31 | "label": "Abbreviation" 32 | }, 33 | { 34 | "fieldname": "customs_tariff_number_section", 35 | "fieldtype": "Section Break", 36 | "label": "Customs Tariff Number" 37 | }, 38 | { 39 | "fieldname": "greige_fabric_tariff", 40 | "fieldtype": "Table", 41 | "label": "Greige Fabric Tariff Numbers", 42 | "options": "Fabric Tariff Number" 43 | }, 44 | { 45 | "fieldname": "ready_fabric_tariff", 46 | "fieldtype": "Table", 47 | "label": "Ready Fabric Tariff Numbers", 48 | "options": "Fabric Tariff Number" 49 | }, 50 | { 51 | "fieldname": "printed_fabric_tariff", 52 | "fieldtype": "Table", 53 | "label": "Printed Fabric Tariff Numbers", 54 | "options": "Fabric Tariff Number" 55 | } 56 | ], 57 | "index_web_pages_for_search": 1, 58 | "links": [ 59 | { 60 | "group": "Items", 61 | "link_doctype": "Item", 62 | "link_fieldname": "fabric_material" 63 | } 64 | ], 65 | "modified": "2024-03-19 18:23:07.369635", 66 | "modified_by": "Administrator", 67 | "module": "Textile", 68 | "name": "Fabric Material", 69 | "naming_rule": "By fieldname", 70 | "owner": "Administrator", 71 | "permissions": [ 72 | { 73 | "create": 1, 74 | "delete": 1, 75 | "email": 1, 76 | "export": 1, 77 | "print": 1, 78 | "read": 1, 79 | "report": 1, 80 | "role": "System Manager", 81 | "share": 1, 82 | "write": 1 83 | }, 84 | { 85 | "email": 1, 86 | "export": 1, 87 | "print": 1, 88 | "read": 1, 89 | "report": 1, 90 | "role": "Item Manager", 91 | "share": 1 92 | }, 93 | { 94 | "email": 1, 95 | "export": 1, 96 | "print": 1, 97 | "read": 1, 98 | "report": 1, 99 | "role": "Pretreatment Sales User", 100 | "share": 1 101 | }, 102 | { 103 | "email": 1, 104 | "print": 1, 105 | "read": 1, 106 | "report": 1, 107 | "role": "Print Sales User", 108 | "share": 1 109 | }, 110 | { 111 | "role": "All", 112 | "select": 1 113 | } 114 | ], 115 | "quick_entry": 1, 116 | "search_fields": "abbreviation", 117 | "sort_field": "idx", 118 | "sort_order": "DESC", 119 | "states": [], 120 | "track_changes": 1 121 | } -------------------------------------------------------------------------------- /textile/textile/doctype/fabric_material/fabric_material.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, ParaLogic and contributors 2 | # For license information, please see license.txt 3 | import frappe 4 | from frappe.utils import flt 5 | from frappe.model.document import Document 6 | 7 | 8 | class FabricMaterial(Document): 9 | def get_tariff_number(self, textile_item_type, fabric_gsm): 10 | fabric_gsm = flt(fabric_gsm) 11 | 12 | table_field = None 13 | if textile_item_type == "Greige Fabric": 14 | table_field = "greige_fabric_tariff" 15 | elif textile_item_type == "Ready Fabric": 16 | table_field = "ready_fabric_tariff" 17 | elif textile_item_type == "Printed Design": 18 | table_field = "printed_fabric_tariff" 19 | 20 | if not table_field: 21 | return None 22 | 23 | for d in self.get(table_field): 24 | if d.gsm_low and fabric_gsm < d.gsm_low: 25 | continue 26 | if d.gsm_high and fabric_gsm > d.gsm_high: 27 | continue 28 | 29 | return d.customs_tariff_number 30 | 31 | 32 | def update_item_tariff_numbers(fabric_material): 33 | frappe.has_permission("Item", ptype="write", throw=True) 34 | 35 | material_doc = frappe.get_doc("Fabric Material", fabric_material) 36 | items = frappe.get_all("Item", filters={"fabric_material": fabric_material}, 37 | fields=["name", "textile_item_type", "fabric_gsm"]) 38 | 39 | for d in items: 40 | tariff_number = material_doc.get_tariff_number(d.textile_item_type, d.fabric_gsm) 41 | if tariff_number: 42 | frappe.db.set_value("Item", d.name, "customs_tariff_number", tariff_number, update_modified=False) 43 | -------------------------------------------------------------------------------- /textile/textile/doctype/fabric_material/test_fabric_material.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, ParaLogic and Contributors 2 | # See license.txt 3 | 4 | # import frappe 5 | from frappe.tests.utils import FrappeTestCase 6 | 7 | 8 | class TestFabricMaterial(FrappeTestCase): 9 | pass 10 | -------------------------------------------------------------------------------- /textile/textile/doctype/fabric_tariff_number/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/textile/doctype/fabric_tariff_number/__init__.py -------------------------------------------------------------------------------- /textile/textile/doctype/fabric_tariff_number/fabric_tariff_number.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "allow_rename": 1, 4 | "creation": "2024-02-03 15:01:42.251516", 5 | "doctype": "DocType", 6 | "editable_grid": 1, 7 | "engine": "InnoDB", 8 | "field_order": [ 9 | "customs_tariff_number", 10 | "gsm_low", 11 | "gsm_high" 12 | ], 13 | "fields": [ 14 | { 15 | "fieldname": "customs_tariff_number", 16 | "fieldtype": "Link", 17 | "in_list_view": 1, 18 | "label": "Customs Tariff Number", 19 | "options": "Customs Tariff Number", 20 | "reqd": 1 21 | }, 22 | { 23 | "columns": 2, 24 | "fieldname": "gsm_low", 25 | "fieldtype": "Float", 26 | "in_list_view": 1, 27 | "label": "GSM Lower Limit", 28 | "non_negative": 1, 29 | "precision": "1" 30 | }, 31 | { 32 | "columns": 2, 33 | "fieldname": "gsm_high", 34 | "fieldtype": "Float", 35 | "in_list_view": 1, 36 | "label": "GSM Upper Limit", 37 | "non_negative": 1, 38 | "precision": "1" 39 | } 40 | ], 41 | "index_web_pages_for_search": 1, 42 | "istable": 1, 43 | "links": [], 44 | "modified": "2024-02-03 15:04:51.193616", 45 | "modified_by": "Administrator", 46 | "module": "Textile", 47 | "name": "Fabric Tariff Number", 48 | "owner": "Administrator", 49 | "permissions": [], 50 | "sort_field": "modified", 51 | "sort_order": "DESC", 52 | "states": [] 53 | } -------------------------------------------------------------------------------- /textile/textile/doctype/fabric_tariff_number/fabric_tariff_number.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2024, ParaLogic and contributors 2 | # For license information, please see license.txt 3 | 4 | # import frappe 5 | from frappe.model.document import Document 6 | 7 | class FabricTariffNumber(Document): 8 | pass 9 | -------------------------------------------------------------------------------- /textile/textile/doctype/fabric_type/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/textile/doctype/fabric_type/__init__.py -------------------------------------------------------------------------------- /textile/textile/doctype/fabric_type/fabric_type.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, ParaLogic and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('Fabric Type', { 5 | // refresh: function(frm) { 6 | 7 | // } 8 | }); 9 | -------------------------------------------------------------------------------- /textile/textile/doctype/fabric_type/fabric_type.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "allow_rename": 1, 4 | "autoname": "field:fabric_type", 5 | "creation": "2023-02-08 17:19:58.165842", 6 | "default_view": "List", 7 | "doctype": "DocType", 8 | "editable_grid": 1, 9 | "engine": "InnoDB", 10 | "field_order": [ 11 | "fabric_type", 12 | "abbreviation" 13 | ], 14 | "fields": [ 15 | { 16 | "allow_in_quick_entry": 1, 17 | "fieldname": "fabric_type", 18 | "fieldtype": "Data", 19 | "label": "Fabric Type", 20 | "reqd": 1, 21 | "unique": 1 22 | }, 23 | { 24 | "allow_in_quick_entry": 1, 25 | "fieldname": "abbreviation", 26 | "fieldtype": "Data", 27 | "in_list_view": 1, 28 | "label": "Abbreviation" 29 | } 30 | ], 31 | "index_web_pages_for_search": 1, 32 | "links": [ 33 | { 34 | "group": "Items", 35 | "link_doctype": "Item", 36 | "link_fieldname": "fabric_type" 37 | } 38 | ], 39 | "modified": "2024-03-19 18:22:31.914570", 40 | "modified_by": "Administrator", 41 | "module": "Textile", 42 | "name": "Fabric Type", 43 | "naming_rule": "By fieldname", 44 | "owner": "Administrator", 45 | "permissions": [ 46 | { 47 | "create": 1, 48 | "delete": 1, 49 | "email": 1, 50 | "export": 1, 51 | "print": 1, 52 | "read": 1, 53 | "report": 1, 54 | "role": "System Manager", 55 | "share": 1, 56 | "write": 1 57 | }, 58 | { 59 | "email": 1, 60 | "export": 1, 61 | "print": 1, 62 | "read": 1, 63 | "report": 1, 64 | "role": "Item Manager", 65 | "share": 1 66 | }, 67 | { 68 | "read": 1, 69 | "report": 1, 70 | "role": "Pretreatment Sales User" 71 | }, 72 | { 73 | "read": 1, 74 | "report": 1, 75 | "role": "Print Sales User" 76 | }, 77 | { 78 | "role": "All", 79 | "select": 1 80 | } 81 | ], 82 | "quick_entry": 1, 83 | "search_fields": "abbreviation", 84 | "sort_field": "idx", 85 | "sort_order": "DESC", 86 | "states": [] 87 | } -------------------------------------------------------------------------------- /textile/textile/doctype/fabric_type/fabric_type.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, ParaLogic and contributors 2 | # For license information, please see license.txt 3 | 4 | # import frappe 5 | from frappe.model.document import Document 6 | 7 | class FabricType(Document): 8 | pass 9 | -------------------------------------------------------------------------------- /textile/textile/doctype/fabric_type/test_fabric_type.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, ParaLogic and Contributors 2 | # See license.txt 3 | 4 | # import frappe 5 | from frappe.tests.utils import FrappeTestCase 6 | 7 | 8 | class TestFabricType(FrappeTestCase): 9 | pass 10 | -------------------------------------------------------------------------------- /textile/textile/doctype/textile_email_digest/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/textile/doctype/textile_email_digest/__init__.py -------------------------------------------------------------------------------- /textile/textile/doctype/textile_email_digest/test_textile_email_digest.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, ParaLogic and Contributors 2 | # See license.txt 3 | 4 | # import frappe 5 | from frappe.tests.utils import FrappeTestCase 6 | 7 | 8 | class TestTextileEmailDigest(FrappeTestCase): 9 | pass 10 | -------------------------------------------------------------------------------- /textile/textile/doctype/textile_email_digest/textile_email_digest.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, ParaLogic and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('Textile Email Digest', { 5 | refresh: function(frm) { 6 | frm.add_custom_button(__("Send Now"), () => frm.trigger('send_now')); 7 | frm.add_custom_button(__("Preview"), () => frm.trigger('preview')); 8 | }, 9 | 10 | send_now: function(frm) { 11 | frm.call({ 12 | method: "send", 13 | doc: frm.doc, 14 | freeze: 1, 15 | }); 16 | }, 17 | 18 | preview: function(frm) { 19 | frappe.prompt([{ 20 | label: __("Date"), fieldname: "date", fieldtype: "Date", default: "Today", 21 | }], (r) => { 22 | frm.call({ 23 | method: "get_preview_html", 24 | doc: frm.doc, 25 | args: { 26 | date: r.date, 27 | }, 28 | callback: (r) => { 29 | const fields = [{ 30 | fieldname: "preview_html", fieldtype: "HTML", options: r.message.message 31 | }]; 32 | 33 | let dialog = new frappe.ui.Dialog({ 34 | title: r.message.subject, fields: fields, size: "medium", 35 | }); 36 | dialog.show(); 37 | } 38 | }); 39 | }, __("Select Reporting Date")); 40 | }, 41 | 42 | addremove_recipients: function(frm) { 43 | return frappe.call({ 44 | method: "get_users", 45 | doc: frm.doc, 46 | callback: function (r) { 47 | if (r.message && !r.exc) { 48 | let dialog_html = ""; 49 | for (let user of r.message) { 50 | dialog_html += ` 51 |
55 | `; 56 | } 57 | 58 | let dialog = new frappe.ui.Dialog({ 59 | title: __('Add/Remove Recipients'), 60 | width: 400, 61 | primary_action: function() { 62 | let receiver_list = []; 63 | for (let input of $(dialog.body).find('input:checked')) { 64 | receiver_list.push($(input).attr('data-id')); 65 | } 66 | frm.set_value('recipient_list', receiver_list.join('\n')); 67 | dialog.hide(); 68 | }, 69 | primary_action_label: __('Update'), 70 | }); 71 | 72 | $(dialog_html).appendTo(dialog.body); 73 | dialog.show(); 74 | } 75 | } 76 | }); 77 | }, 78 | }); 79 | 80 | 81 | -------------------------------------------------------------------------------- /textile/textile/doctype/textile_email_digest/textile_email_digest.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "allow_rename": 1, 4 | "creation": "2023-08-17 17:02:37.123507", 5 | "default_view": "List", 6 | "doctype": "DocType", 7 | "editable_grid": 1, 8 | "engine": "InnoDB", 9 | "field_order": [ 10 | "enabled", 11 | "section_break_gep5c", 12 | "recipient_list", 13 | "addremove_recipients", 14 | "column_break_db1dr", 15 | "email_template", 16 | "send_at_hour_of_the_day", 17 | "do_not_send_if_no_transaction", 18 | "with_container" 19 | ], 20 | "fields": [ 21 | { 22 | "default": "0", 23 | "fieldname": "enabled", 24 | "fieldtype": "Check", 25 | "label": "Enabled" 26 | }, 27 | { 28 | "fieldname": "email_template", 29 | "fieldtype": "Link", 30 | "label": "Email Template", 31 | "mandatory_depends_on": "enabled", 32 | "options": "Email Template" 33 | }, 34 | { 35 | "default": "0", 36 | "fieldname": "send_at_hour_of_the_day", 37 | "fieldtype": "Int", 38 | "label": "Send at Hour of the Day" 39 | }, 40 | { 41 | "fieldname": "column_break_db1dr", 42 | "fieldtype": "Column Break" 43 | }, 44 | { 45 | "description": "Note: Email will not be sent to disabled users", 46 | "fieldname": "recipient_list", 47 | "fieldtype": "Text", 48 | "label": "Recipients", 49 | "mandatory_depends_on": "enabled", 50 | "read_only": 1 51 | }, 52 | { 53 | "fieldname": "addremove_recipients", 54 | "fieldtype": "Button", 55 | "label": "Add/Remove Recipients" 56 | }, 57 | { 58 | "default": "1", 59 | "fieldname": "do_not_send_if_no_transaction", 60 | "fieldtype": "Check", 61 | "label": "Do Not Send If No Transactions" 62 | }, 63 | { 64 | "fieldname": "section_break_gep5c", 65 | "fieldtype": "Section Break" 66 | }, 67 | { 68 | "default": "0", 69 | "fieldname": "with_container", 70 | "fieldtype": "Check", 71 | "label": "Wrap Email in Container" 72 | } 73 | ], 74 | "index_web_pages_for_search": 1, 75 | "issingle": 1, 76 | "links": [], 77 | "modified": "2023-08-23 16:45:13.647258", 78 | "modified_by": "Administrator", 79 | "module": "Textile", 80 | "name": "Textile Email Digest", 81 | "owner": "Administrator", 82 | "permissions": [ 83 | { 84 | "create": 1, 85 | "delete": 1, 86 | "email": 1, 87 | "print": 1, 88 | "read": 1, 89 | "role": "System Manager", 90 | "share": 1, 91 | "write": 1 92 | } 93 | ], 94 | "sort_field": "modified", 95 | "sort_order": "DESC", 96 | "states": [], 97 | "track_changes": 1 98 | } -------------------------------------------------------------------------------- /textile/textile/doctype/textile_item_type/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/textile/doctype/textile_item_type/__init__.py -------------------------------------------------------------------------------- /textile/textile/doctype/textile_item_type/test_textile_item_type.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2024, ParaLogic and Contributors 2 | # See license.txt 3 | 4 | # import frappe 5 | from frappe.tests.utils import FrappeTestCase 6 | 7 | 8 | class TestTextileItemType(FrappeTestCase): 9 | pass 10 | -------------------------------------------------------------------------------- /textile/textile/doctype/textile_item_type/textile_item_type.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024, ParaLogic and contributors 2 | // For license information, please see license.txt 3 | 4 | frappe.ui.form.on('Textile Item Type', { 5 | // refresh: function(frm) { 6 | 7 | // } 8 | }); 9 | -------------------------------------------------------------------------------- /textile/textile/doctype/textile_item_type/textile_item_type.json: -------------------------------------------------------------------------------- 1 | { 2 | "actions": [], 3 | "allow_copy": 1, 4 | "autoname": "field:textile_item_type_name", 5 | "creation": "2024-02-07 14:56:31.583771", 6 | "default_view": "List", 7 | "doctype": "DocType", 8 | "editable_grid": 1, 9 | "engine": "InnoDB", 10 | "field_order": [ 11 | "textile_item_type_name", 12 | "sorting_idx" 13 | ], 14 | "fields": [ 15 | { 16 | "fieldname": "textile_item_type_name", 17 | "fieldtype": "Data", 18 | "in_list_view": 1, 19 | "label": "Textile Item Type Name", 20 | "options": "DocType", 21 | "reqd": 1, 22 | "unique": 1 23 | }, 24 | { 25 | "fieldname": "sorting_idx", 26 | "fieldtype": "Int", 27 | "label": "Sorting Idx" 28 | } 29 | ], 30 | "in_create": 1, 31 | "links": [], 32 | "modified": "2024-02-07 14:56:31.583771", 33 | "modified_by": "Administrator", 34 | "module": "Textile", 35 | "name": "Textile Item Type", 36 | "naming_rule": "By fieldname", 37 | "owner": "Administrator", 38 | "permissions": [ 39 | { 40 | "email": 1, 41 | "export": 1, 42 | "print": 1, 43 | "read": 1, 44 | "report": 1, 45 | "role": "System Manager", 46 | "share": 1 47 | }, 48 | { 49 | "report": 1, 50 | "role": "All", 51 | "select": 1 52 | } 53 | ], 54 | "sort_field": "sorting_idx", 55 | "sort_order": "ASC", 56 | "states": [], 57 | "track_changes": 1 58 | } -------------------------------------------------------------------------------- /textile/textile/doctype/textile_item_type/textile_item_type.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2024, ParaLogic and contributors 2 | # For license information, please see license.txt 3 | 4 | # import frappe 5 | from frappe.model.document import Document 6 | 7 | class TextileItemType(Document): 8 | pass 9 | -------------------------------------------------------------------------------- /textile/textile/report/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/textile/report/__init__.py -------------------------------------------------------------------------------- /textile/textile/report/fabric_delivery_register/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/textile/report/fabric_delivery_register/__init__.py -------------------------------------------------------------------------------- /textile/textile/report/fabric_delivery_register/fabric_delivery_register.json: -------------------------------------------------------------------------------- 1 | { 2 | "add_total_row": 1, 3 | "columns": [], 4 | "creation": "2023-09-14 16:17:55.208916", 5 | "disable_prepared_report": 0, 6 | "disabled": 0, 7 | "docstatus": 0, 8 | "doctype": "Report", 9 | "filters": [], 10 | "idx": 0, 11 | "is_standard": "Yes", 12 | "modified": "2024-03-19 18:14:50.285442", 13 | "modified_by": "Administrator", 14 | "module": "Textile", 15 | "name": "Fabric Delivery Register", 16 | "owner": "Administrator", 17 | "prepared_report": 0, 18 | "ref_doctype": "Delivery Note", 19 | "report_name": "Fabric Delivery Register", 20 | "report_type": "Script Report", 21 | "roles": [ 22 | { 23 | "role": "Accounts User" 24 | }, 25 | { 26 | "role": "Pretreatment Sales User" 27 | }, 28 | { 29 | "role": "Print Sales User" 30 | } 31 | ] 32 | } -------------------------------------------------------------------------------- /textile/textile/report/fabric_delivery_register/fabric_delivery_register.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2023, ParaLogic and contributors 2 | # For license information, please see license.txt 3 | 4 | # import frappe 5 | from frappe import _ 6 | from erpnext.selling.report.sales_details.sales_details import SalesPurchaseDetailsReport 7 | 8 | 9 | def execute(filters=None): 10 | updated_filters = { 11 | "qty_only": 1, 12 | "show_packing_slip": 1, 13 | } 14 | updated_filters.update(filters or {}) 15 | 16 | return FabricSalesPurchaseReport(updated_filters, doctype="Delivery Note").run() 17 | 18 | 19 | class FabricSalesPurchaseReport(SalesPurchaseDetailsReport): 20 | def set_fieldnames(self): 21 | super().set_fieldnames() 22 | self.qty_fields += ["return_qty", "total_qty", "panel_qty"] 23 | 24 | def get_select_fields_and_joins(self): 25 | select_fields, joins = super().get_select_fields_and_joins() 26 | 27 | joins.append("left join `tabItem` fabric on fabric.name = im.fabric_item") 28 | 29 | select_fields += [ 30 | "im.fabric_item", 31 | "fabric.item_name as fabric_item_name", 32 | "im.textile_item_type", 33 | "i.print_order", 34 | "i.pretreatment_order", 35 | "i.is_return_fabric", 36 | "i.panel_qty", 37 | ] 38 | 39 | return select_fields, joins 40 | 41 | def get_conditions(self): 42 | conditions = super().get_conditions() 43 | 44 | if self.filters.fabric_item: 45 | conditions.append("(im.fabric_item = %(fabric_item)s or (im.item_code = %(fabric_item)s))") 46 | 47 | if self.filters.fabric_material: 48 | conditions.append("im.fabric_material = %(fabric_material)s") 49 | 50 | if self.filters.fabric_type: 51 | conditions.append("im.fabric_type = %(fabric_type)s") 52 | 53 | return conditions 54 | 55 | def prepare_data(self): 56 | super().prepare_data() 57 | 58 | for d in self.entries: 59 | if not d.panel_qty: 60 | d.panel_qty = None 61 | 62 | d.total_qty = d.qty 63 | if d.is_return_fabric: 64 | d.return_qty = d.qty 65 | d.qty = None 66 | 67 | if d.textile_item_type in ("Ready Fabric", "Greige Fabric"): 68 | d.fabric_item = d.item_code 69 | d.fabric_item_name = d.item_name 70 | 71 | def calculate_group_totals(self, data, group_field, group_value, grouped_by): 72 | totals = super().calculate_group_totals(data, group_field, group_value, grouped_by) 73 | 74 | if totals.get("parent"): 75 | pretreatment_orders = set([d.pretreatment_order for d in data if d.pretreatment_order]) 76 | if len(pretreatment_orders) == 1: 77 | totals.pretreatment_order = list(pretreatment_orders)[0] 78 | 79 | print_orders = set([d.print_order for d in data if d.print_order]) 80 | if len(print_orders) == 1: 81 | totals.print_order = list(print_orders)[0] 82 | 83 | fabric_items = set([d.fabric_item for d in data if d.fabric_item]) 84 | if len(fabric_items) == 1: 85 | totals['fabric_item'] = list(fabric_items)[0] 86 | 87 | if totals.get('fabric_item'): 88 | totals['fabric_item_name'] = data[0].fabric_item_name 89 | 90 | return totals 91 | 92 | def fieldname_to_doctype(self, fieldname): 93 | if fieldname == "fabric_item": 94 | return "Item" 95 | 96 | return super().fieldname_to_doctype(fieldname) 97 | 98 | def get_columns(self): 99 | columns = super().get_columns() 100 | 101 | if "fabric_item" in self.group_by or not self.filters.totals_only: 102 | item_code_index = next((i for i, c in enumerate(columns) if c.get("fieldname") == "item_code"), 1) 103 | columns.insert(item_code_index, { 104 | "label": _("Fabric Name"), 105 | "fieldname": "fabric_item_name", 106 | "fieldtype": "Data", 107 | "width": 150 108 | }) 109 | 110 | qty_index = next((i for i, c in enumerate(columns) if c.get("fieldname") == "qty"), 100) 111 | columns[qty_index+1:qty_index+1] = [ 112 | { 113 | "label": _("Return Qty"), 114 | "fieldname": "return_qty", 115 | "fieldtype": "Float", 116 | "width": 80 117 | }, 118 | { 119 | "label": _("Total Qty"), 120 | "fieldname": "total_qty", 121 | "fieldtype": "Float", 122 | "width": 80 123 | }, 124 | { 125 | "label": _("Panels"), 126 | "fieldname": "panel_qty", 127 | "fieldtype": "Float", 128 | "precision": 1, 129 | "width": 70 130 | }, 131 | ] 132 | 133 | packing_slip_index = next((i for i, c in enumerate(columns) if c.get("fieldname") == "packing_slip"), 100) 134 | columns[packing_slip_index + 1:packing_slip_index + 1] = [ 135 | { 136 | "label": _("Print Order"), 137 | "fieldname": "print_order", 138 | "fieldtype": "Link", 139 | "options": "Print Order", 140 | "width": 100 141 | }, 142 | { 143 | "label": _("Pretreatment Order"), 144 | "fieldname": "pretreatment_order", 145 | "fieldtype": "Link", 146 | "options": "Pretreatment Order", 147 | "width": 100 148 | }, 149 | ] 150 | 151 | return columns 152 | -------------------------------------------------------------------------------- /textile/textile/report/fabric_ledger/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/textile/report/fabric_ledger/__init__.py -------------------------------------------------------------------------------- /textile/textile/report/fabric_ledger/fabric_ledger.html: -------------------------------------------------------------------------------- 1 | 35 | 36 |
37 |

{%= __("Fabric Ledger") %}

38 | 39 |
40 | 41 | 42 |
43 |
44 |
45 | {%= __("From Date") %}: 46 | {%= frappe.datetime.str_to_user(filters.from_date) %} 47 |
48 | 49 |
50 | {%= __("To Date") %}: 51 | {%= frappe.datetime.str_to_user(filters.to_date) %} 52 |
53 |
54 | 55 |
56 | {% if filters.customer %} 57 |
58 | {%= __("Customer") %}: 59 | {%= filters.customer %} 60 |
61 | {% endif %} 62 | 63 | {% if filters.item_name %} 64 |
65 | {%= __("Fabric") %}: 66 | {%= filters.item_name %} 67 |
68 | {% endif %} 69 |
70 |
71 | 72 |
73 |
74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | {% if !filters.customer %} 86 | 87 | {% endif %} 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | {% for (let d of data) { %} 101 | 102 | 105 | 106 | 110 | 111 | 117 | 118 | {% if !filters.customer %} 119 | 120 | {% endif %} 121 | 122 | 123 | 124 | 127 | 128 | 131 | 132 | 135 | 136 | {% } %} 137 | 138 |
{%= __("Date") %}{%= __("Voucher") %}{%= __("Fabric") %}{%= __("Customer") %}{%= __("UOM") %}{%= __("In") %}{%= __("Out") %}{%= __("Balance") %}
103 | {%= d.posting_date ? frappe.datetime.str_to_user(d.posting_date) : "" %} 104 | 107 |
{%= d.entry_type %}
108 |
{%= d.document_no %}
109 |
112 |
{%= d.fabric_item_name %}
113 | {% if d.is_closing && flt(d.packed_qty_after_transaction, 2) %} 114 |
Packed Qty: {%= format_number(d.packed_qty_after_transaction, null, 2) %}
115 | {% endif %} 116 |
{%= d.party_name %}{%= d.uom %} 125 | {%= d.in_qty ? format_number(d.in_qty, null, 2) : "" %} 126 | 129 | {%= d.out_qty ? format_number(d.out_qty, null, 2) : "" %} 130 | 133 | {%= d.qty_after_transaction != null ? format_number(d.qty_after_transaction, null, 2) : "" %} 134 |
139 |

Printed On {%= frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string()) %}

-------------------------------------------------------------------------------- /textile/textile/report/fabric_ledger/fabric_ledger.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2024, ParaLogic and contributors 2 | // For license information, please see license.txt 3 | /* eslint-disable */ 4 | 5 | frappe.query_reports["Fabric Ledger"] = { 6 | "filters": [ 7 | { 8 | "fieldname": "company", 9 | "label": __("Company"), 10 | "fieldtype": "Link", 11 | "options": "Company", 12 | "default": frappe.defaults.get_user_default("Company"), 13 | "bold": 1 14 | }, 15 | { 16 | "fieldname": "from_date", 17 | "label": __("From Date"), 18 | "fieldtype": "Date", 19 | "default": frappe.datetime.add_months(frappe.datetime.get_today(), -1), 20 | "reqd": 1 21 | }, 22 | { 23 | "fieldname": "to_date", 24 | "label": __("To Date"), 25 | "fieldtype": "Date", 26 | "default": frappe.datetime.get_today(), 27 | "reqd": 1 28 | }, 29 | { 30 | "fieldname": "customer", 31 | "label": __("Customer"), 32 | "fieldtype": "Link", 33 | "options": "Customer" 34 | }, 35 | { 36 | "fieldname": "item_code", 37 | "label": __("Fabric Item"), 38 | "fieldtype": "Link", 39 | "options": "Item", 40 | "get_query": function() { 41 | let out = { 42 | query: "erpnext.controllers.queries.item_query", 43 | filters: { 44 | "include_disabled": 1, 45 | "textile_item_type": ["in", ["Greige Fabric", "Ready Fabric"]] 46 | } 47 | } 48 | 49 | let customer = frappe.query_report.get_filter_value("customer"); 50 | if (customer) { 51 | out.filters['customer'] = customer; 52 | } 53 | 54 | return out; 55 | }, 56 | on_change: function() { 57 | let item_code = frappe.query_report.get_filter_value('item_code'); 58 | if (!item_code) { 59 | frappe.query_report.set_filter_value('item_name', ""); 60 | } else { 61 | frappe.db.get_value("Item", item_code, ['item_name', 'customer'], function(value) { 62 | frappe.query_report.set_filter_value('customer', value['customer']); 63 | frappe.query_report.set_filter_value('item_name', value['item_name']); 64 | }); 65 | } 66 | } 67 | }, 68 | { 69 | "fieldname": "item_name", 70 | "label": __("Fabric Name"), 71 | "fieldtype": "Data", 72 | "read_only": 1, 73 | }, 74 | { 75 | "fieldname": "batch_no", 76 | "label": __("Batch No"), 77 | "fieldtype": "Link", 78 | "options": "Batch", 79 | "get_query": function() { 80 | let filters = {}; 81 | 82 | let item_code = frappe.query_report.get_filter_value("item_code"); 83 | if (item_code) { 84 | filters['item'] = item_code; 85 | } 86 | 87 | return { 88 | filters: filters 89 | }; 90 | }, 91 | }, 92 | { 93 | "fieldname": "hide_internal_entries", 94 | "label": __("Hide Internal Entries"), 95 | "fieldtype": "Check", 96 | "default": 1, 97 | }, 98 | { 99 | "fieldname": "merge_print_production", 100 | "label": __("Merge Print Production Entries"), 101 | "fieldtype": "Check", 102 | "default": 1, 103 | }, 104 | { 105 | "fieldname": "combine_greige_ready", 106 | "label": __("Combine Greige and Ready Fabric"), 107 | "fieldtype": "Check", 108 | "default": 1, 109 | }, 110 | { 111 | "fieldname": "orientation", 112 | "label": __("Orientation"), 113 | "fieldtype": "Data", 114 | "default": "Portrait", 115 | "hidden": 1, 116 | }, 117 | ], 118 | formatter: function(value, row, column, data, default_formatter) { 119 | var style = {}; 120 | 121 | $.each(['in_qty', 'out_qty'], function (i, f) { 122 | if (flt(value)) { 123 | if (column.fieldname === 'in_qty') { 124 | style['color'] = 'green'; 125 | } 126 | if (column.fieldname === 'out_qty') { 127 | style['color'] = 'red'; 128 | } 129 | 130 | if (data.is_internal_entry && ['in_qty', 'out_qty'].includes(column.fieldname)) { 131 | style['color'] = 'var(--gray-600)'; 132 | } 133 | } 134 | }); 135 | 136 | return default_formatter(value, row, column, data, {css: style}); 137 | }, 138 | }; 139 | -------------------------------------------------------------------------------- /textile/textile/report/fabric_ledger/fabric_ledger.json: -------------------------------------------------------------------------------- 1 | { 2 | "add_total_row": 0, 3 | "columns": [], 4 | "creation": "2024-05-12 20:11:50.864999", 5 | "disable_prepared_report": 0, 6 | "disabled": 0, 7 | "docstatus": 0, 8 | "doctype": "Report", 9 | "filters": [], 10 | "idx": 0, 11 | "is_standard": "Yes", 12 | "modified": "2024-05-12 20:11:50.864999", 13 | "modified_by": "Administrator", 14 | "module": "Textile", 15 | "name": "Fabric Ledger", 16 | "owner": "Administrator", 17 | "prepared_report": 0, 18 | "ref_doctype": "Stock Ledger Entry", 19 | "report_name": "Fabric Ledger", 20 | "report_type": "Script Report", 21 | "roles": [ 22 | { 23 | "role": "Stock User" 24 | }, 25 | { 26 | "role": "Accounts User" 27 | }, 28 | { 29 | "role": "Sales User" 30 | }, 31 | { 32 | "role": "Sales User (Read Only)" 33 | }, 34 | { 35 | "role": "Manufacturing User" 36 | }, 37 | { 38 | "role": "Purchase User" 39 | }, 40 | { 41 | "role": "Delivery User" 42 | } 43 | ] 44 | } -------------------------------------------------------------------------------- /textile/textile/report/fabric_packing_list/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/textile/report/fabric_packing_list/__init__.py -------------------------------------------------------------------------------- /textile/textile/report/fabric_packing_list/fabric_packing_list.html: -------------------------------------------------------------------------------- 1 | 41 | 42 |
43 |

{%= __("Fabric Packing List") %}

44 |
45 | {% if subtitle %} 46 | {%= subtitle %} 47 |
48 | {% endif %} 49 |
50 | 51 | {% var show_design_image = filters.show_image_in_print && (data || []).filter(d => d.image).length; %} 52 | {% var show_date = (data || []).filter(d => d.posting_date).length; %} 53 | 54 | 55 | 56 | 57 | 58 | 59 | {% if show_date %} 60 | 61 | {% endif %} 62 | 63 | 64 | 65 | {% if show_design_image %} 66 | 67 | {% endif %} 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | {% for (let d of data) { %} 78 | 79 | 80 | 81 | 82 | {% if show_date %} 83 | 84 | {% endif %} 85 | 86 | 87 | 88 | {% if show_design_image %} 89 | 94 | {% endif %} 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | {% } %} 103 | 104 |
{%= __("Sr.") %}{%= __("Reference") %}{%= __("Date") %}{%= __("Item") %}{%= __("Design") %}{%= __("Qty") %}{%= __("Return") %}{%= __("Total") %}{%= __("UOM") %}{%= __("Panels") %}
{%= d._group_idx %}{%= d.reference_type != "Item" ? d.reference : "" %}{%= d.posting_date ? frappe.datetime.str_to_user(d.posting_date) : "" %}{%= d.item_name %} 90 | {% if (d.image) { %} 91 | 92 | {% } %} 93 | {%= d.qty ? format_number(d.qty, null, 2) : "" %}{%= d.return_qty ? format_number(d.return_qty, null, 2) : "" %}{%= d.total_qty ? format_number(d.total_qty, null, 2) : "" %}{%= d.uom %}{%= d.panel_qty ? format_number(d.panel_qty, null, 1) : "" %}
-------------------------------------------------------------------------------- /textile/textile/report/fabric_packing_list/fabric_packing_list.js: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2023, ParaLogic and contributors 2 | // For license information, please see license.txt 3 | /* eslint-disable */ 4 | 5 | frappe.provide("textile"); 6 | 7 | textile.group_field_opts_fpl = [ 8 | "", 9 | "Group by Package", 10 | "Group by Customer", 11 | "Group by Print Order", 12 | "Group by Fabric Item", 13 | "Group by Design Item", 14 | ] 15 | 16 | frappe.query_reports["Fabric Packing List"] = { 17 | "filters": [ 18 | { 19 | fieldname: "company", 20 | label: __("Company"), 21 | fieldtype: "Link", 22 | options: "Company", 23 | default: frappe.defaults.get_user_default("Company"), 24 | reqd: 1, 25 | print_hide: 1, 26 | }, 27 | { 28 | fieldname: "customer", 29 | label: __("Customer"), 30 | fieldtype: "Link", 31 | options: "Customer", 32 | on_change: () => { 33 | var customer = frappe.query_report.get_filter_value('customer'); 34 | if (customer) { 35 | frappe.db.get_value('Customer', customer, ["customer_name"], function(value) { 36 | frappe.query_report.set_filter_value('customer_name', value["customer_name"]); 37 | }); 38 | } else { 39 | frappe.query_report.set_filter_value('customer_name', ""); 40 | } 41 | }, 42 | print_hide: 1, 43 | }, 44 | { 45 | fieldname: "customer_name", 46 | label: __("Customer Name"), 47 | fieldtype: "Data", 48 | read_only: 1, 49 | hidden: 1, 50 | }, 51 | { 52 | "fieldname":"print_order", 53 | "label": __("Print Order"), 54 | "fieldtype": "MultiSelectList", 55 | get_data: function(txt) { 56 | let filters = { 57 | company: frappe.query_report.get_filter_value("company") 58 | } 59 | customer = frappe.query_report.get_filter_value("customer"); 60 | if (customer) { 61 | filters.customer = customer; 62 | } 63 | return frappe.db.get_link_options('Print Order', txt, filters); 64 | } 65 | }, 66 | { 67 | fieldname: "packing_slip", 68 | label: __("Package"), 69 | fieldtype: "Link", 70 | options: "Packing Slip", 71 | }, 72 | { 73 | fieldname: "package_type", 74 | label: __("Package Type"), 75 | fieldtype: "Link", 76 | options: "Package Type", 77 | }, 78 | { 79 | fieldname: "fabric_item", 80 | label: __("Fabric Item"), 81 | fieldtype: "Link", 82 | options: "Item", 83 | get_query: function() { 84 | return { 85 | query: "erpnext.controllers.queries.item_query", 86 | filters: { 87 | 'textile_item_type': "Ready Fabric" 88 | } 89 | }; 90 | }, 91 | on_change: () => { 92 | var item = frappe.query_report.get_filter_value('fabric_item'); 93 | if (item) { 94 | frappe.db.get_value('Item', item, ["item_name"], function(value) { 95 | frappe.query_report.set_filter_value('fabric_item_name', value["item_name"]); 96 | }); 97 | } else { 98 | frappe.query_report.set_filter_value('fabric_item_name', ""); 99 | } 100 | }, 101 | }, 102 | { 103 | fieldname: "fabric_item_name", 104 | label: __("Fabric Item Name"), 105 | fieldtype: "Data", 106 | read_only: 1, 107 | hidden: 1, 108 | }, 109 | { 110 | fieldname: "fabric_material", 111 | label: __("Fabric Material"), 112 | fieldtype: "Link", 113 | options: "Fabric Material", 114 | }, 115 | { 116 | fieldname: "fabric_type", 117 | label: __("Fabric Type"), 118 | fieldtype: "Link", 119 | options: "Fabric Type", 120 | }, 121 | { 122 | fieldname: "warehouse", 123 | label: __("Warehouse"), 124 | fieldtype: "Link", 125 | options: "Warehouse", 126 | get_query: function() { 127 | return { 128 | filters: {'company': frappe.query_report.get_filter_value("company")} 129 | } 130 | }, 131 | }, 132 | { 133 | fieldname: "group_by_1", 134 | label: __("Group By Level 1"), 135 | fieldtype: "Select", 136 | options: textile.group_field_opts_fpl, 137 | default: "", 138 | print_hide: 1, 139 | }, 140 | { 141 | fieldname: "group_by_2", 142 | label: __("Group By Level 2"), 143 | fieldtype: "Select", 144 | options: textile.group_field_opts_fpl, 145 | default: "Group by Package", 146 | print_hide: 1, 147 | }, 148 | { 149 | fieldname: "totals_only", 150 | label: __("Group Totals Only"), 151 | fieldtype: "Check", 152 | print_hide: 1, 153 | }, 154 | { 155 | fieldname: "show_delivered", 156 | label: __("Show Delivered"), 157 | fieldtype: "Check" 158 | }, 159 | { 160 | fieldname: "show_image_in_print", 161 | label: __("Show Design Image in Print"), 162 | fieldtype: "Check", 163 | }, 164 | ], 165 | formatter: function(value, row, column, data, default_formatter) { 166 | var style = {}; 167 | 168 | if (data.is_return_fabric) { 169 | style['color'] = 'var(--alert-text-info)'; 170 | } 171 | 172 | return default_formatter(value, row, column, data, {css: style}); 173 | }, 174 | initial_depth: 1 175 | }; 176 | -------------------------------------------------------------------------------- /textile/textile/report/fabric_packing_list/fabric_packing_list.json: -------------------------------------------------------------------------------- 1 | { 2 | "add_total_row": 1, 3 | "columns": [], 4 | "creation": "2023-09-15 00:43:26.395314", 5 | "disable_prepared_report": 0, 6 | "disabled": 0, 7 | "docstatus": 0, 8 | "doctype": "Report", 9 | "filters": [], 10 | "idx": 0, 11 | "is_standard": "Yes", 12 | "modified": "2024-03-19 18:15:17.631848", 13 | "modified_by": "Administrator", 14 | "module": "Textile", 15 | "name": "Fabric Packing List", 16 | "owner": "Administrator", 17 | "prepared_report": 0, 18 | "ref_doctype": "Packing Slip", 19 | "report_name": "Fabric Packing List", 20 | "report_type": "Script Report", 21 | "roles": [ 22 | { 23 | "role": "Accounts User" 24 | }, 25 | { 26 | "role": "Pretreatment Sales User" 27 | }, 28 | { 29 | "role": "Print Sales User" 30 | } 31 | ] 32 | } -------------------------------------------------------------------------------- /textile/www/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ParaLogicTech/textile/5f7d91ee5e6ea5c9648508ad1e235aae7addae55/textile/www/__init__.py --------------------------------------------------------------------------------