Compare commits

..

No commits in common. "e2746b83bb32e055c022d30f90d320b9ad5aa769" and "8ebd77540c1c68f294cdc9841c06061f76398bf8" have entirely different histories.

17 changed files with 402 additions and 14908 deletions

File diff suppressed because it is too large Load diff

View file

@ -1,154 +0,0 @@
[
{
"company": "Sprinklers Northwest",
"docstatus": 0,
"doctype": "Bid Meeting Note Form",
"fields": [
{
"column": 1,
"conditional_on_field": null,
"conditional_on_value": null,
"default_value": null,
"doctype_for_select": null,
"doctype_label_field": null,
"help_text": "Indicate if a locate is needed for this project.",
"include_options": 0,
"label": "Locate Needed",
"options": null,
"order": 0,
"parent": "SNW Install Bid Meeting Notes",
"parentfield": "fields",
"parenttype": "Bid Meeting Note Form",
"read_only": 0,
"required": 0,
"row": 1,
"type": "Check"
},
{
"column": 2,
"conditional_on_field": null,
"conditional_on_value": null,
"default_value": null,
"doctype_for_select": null,
"doctype_label_field": null,
"help_text": "Indicate if a permit is needed for this project.",
"include_options": 0,
"label": "Permit Needed",
"options": null,
"order": 0,
"parent": "SNW Install Bid Meeting Notes",
"parentfield": "fields",
"parenttype": "Bid Meeting Note Form",
"read_only": 0,
"required": 0,
"row": 1,
"type": "Check"
},
{
"column": 3,
"conditional_on_field": null,
"conditional_on_value": null,
"default_value": null,
"doctype_for_select": null,
"doctype_label_field": null,
"help_text": "Indicate if a backflow test is required after installation.",
"include_options": 0,
"label": "Back Flow Test Required",
"options": null,
"order": 0,
"parent": "SNW Install Bid Meeting Notes",
"parentfield": "fields",
"parenttype": "Bid Meeting Note Form",
"read_only": 0,
"required": 0,
"row": 1,
"type": "Check"
},
{
"column": 1,
"conditional_on_field": null,
"conditional_on_value": null,
"default_value": null,
"doctype_for_select": null,
"doctype_label_field": null,
"help_text": null,
"include_options": 0,
"label": "Machine Access",
"options": null,
"order": 0,
"parent": "SNW Install Bid Meeting Notes",
"parentfield": "fields",
"parenttype": "Bid Meeting Note Form",
"read_only": 0,
"required": 0,
"row": 2,
"type": "Check"
},
{
"column": 2,
"conditional_on_field": "Machine Access",
"conditional_on_value": null,
"default_value": null,
"doctype_for_select": null,
"doctype_label_field": null,
"help_text": null,
"include_options": 1,
"label": "Machines",
"options": "MT, Skip Steer, Excavator-E-50, Link Belt, Tre?, Forks, Auger, Backhoe, Loader, Duzer",
"order": 0,
"parent": "SNW Install Bid Meeting Notes",
"parentfield": "fields",
"parenttype": "Bid Meeting Note Form",
"read_only": 0,
"required": 0,
"row": 2,
"type": "Multi-Select"
},
{
"column": 0,
"conditional_on_field": null,
"conditional_on_value": null,
"default_value": null,
"doctype_for_select": null,
"doctype_label_field": null,
"help_text": null,
"include_options": 0,
"label": "Materials Required",
"options": null,
"order": 0,
"parent": "SNW Install Bid Meeting Notes",
"parentfield": "fields",
"parenttype": "Bid Meeting Note Form",
"read_only": 0,
"required": 0,
"row": 3,
"type": "Check"
},
{
"column": 0,
"conditional_on_field": "Materials Required",
"conditional_on_value": null,
"default_value": null,
"doctype_for_select": "Item",
"doctype_label_field": "itemName",
"help_text": null,
"include_options": 0,
"label": "Materials",
"options": null,
"order": 0,
"parent": "SNW Install Bid Meeting Notes",
"parentfield": "fields",
"parenttype": "Bid Meeting Note Form",
"read_only": 0,
"required": 0,
"row": 4,
"type": "Multi-Select w/ Quantity"
}
],
"modified": "2026-02-15 02:33:43.948485",
"name": "SNW Install Bid Meeting Notes",
"notes": null,
"project_template": "",
"title": "SNW Install Bid Meeting Notes"
}
]

View file

@ -1,530 +0,0 @@
[
{
"abbr": "VS",
"accumulated_depreciation_account": "Accumulated Depreciation - VS",
"allow_account_creation_against_child_company": 0,
"asset_received_but_not_billed": "Asset Received But Not Billed - VS",
"auto_err_frequency": "Daily",
"auto_exchange_rate_revaluation": 0,
"book_advance_payments_in_separate_party_account": 0,
"capital_work_in_progress_account": "CWIP Account - VS",
"chart_of_accounts": "Standard",
"company_description": null,
"company_logo": null,
"company_name": "Veritas Stone",
"cost_center": "Main - VS",
"country": "United States",
"create_chart_of_accounts_based_on": "Standard Template",
"credit_limit": 0.0,
"date_of_commencement": null,
"date_of_establishment": null,
"date_of_incorporation": null,
"default_advance_paid_account": null,
"default_advance_received_account": null,
"default_bank_account": null,
"default_buying_terms": null,
"default_cash_account": "Cash - VS",
"default_currency": "USD",
"default_deferred_expense_account": null,
"default_deferred_revenue_account": null,
"default_discount_account": null,
"default_employee_advance_account": null,
"default_expense_account": "Cost of Goods Sold - VS",
"default_expense_claim_payable_account": "Creditors - VS",
"default_finance_book": null,
"default_holiday_list": null,
"default_in_transit_warehouse": null,
"default_income_account": "Sales - VS",
"default_inventory_account": "Stock In Hand - VS",
"default_letter_head": null,
"default_operating_cost_account": null,
"default_payable_account": "Creditors - VS",
"default_payroll_payable_account": null,
"default_provisional_account": null,
"default_receivable_account": "Debtors - VS",
"default_sales_contact": null,
"default_selling_terms": null,
"default_warehouse_for_sales_return": null,
"depreciation_cost_center": "Main - VS",
"depreciation_expense_account": "Depreciation - VS",
"disposal_account": "Gain/Loss on Asset Disposal - VS",
"docstatus": 0,
"doctype": "Company",
"domain": null,
"email": null,
"enable_perpetual_inventory": 1,
"enable_provisional_accounting_for_non_stock_items": 0,
"exception_budget_approver_role": null,
"exchange_gain_loss_account": "Exchange Gain/Loss - VS",
"existing_company": null,
"expenses_included_in_asset_valuation": "Expenses Included In Asset Valuation - VS",
"expenses_included_in_valuation": "Expenses Included In Valuation - VS",
"fax": null,
"is_group": 0,
"modified": "2026-02-15 00:56:31.933618",
"monthly_sales_target": 0.0,
"name": "Veritas Stone",
"old_parent": "",
"parent_company": null,
"payment_terms": null,
"phone_no": null,
"reconcile_on_advance_payment_date": 0,
"reconciliation_takes_effect_on": "Oldest Of Invoice Or Advance",
"registration_details": null,
"round_off_account": "Round Off - VS",
"round_off_cost_center": "Main - VS",
"round_off_for_opening": null,
"sales_monthly_history": "{}",
"series_for_depreciation_entry": null,
"stock_adjustment_account": "Stock Adjustment - VS",
"stock_received_but_not_billed": "Stock Received But Not Billed - VS",
"submit_err_jv": 0,
"tax_id": null,
"total_monthly_sales": 0.0,
"transactions_annual_history": "{}",
"unrealized_exchange_gain_loss_account": null,
"unrealized_profit_loss_account": null,
"website": null,
"write_off_account": "Write Off - VS"
},
{
"abbr": "DL",
"accumulated_depreciation_account": "Accumulated Depreciation - DL",
"allow_account_creation_against_child_company": 0,
"asset_received_but_not_billed": "Asset Received But Not Billed - DL",
"auto_err_frequency": "Daily",
"auto_exchange_rate_revaluation": 0,
"book_advance_payments_in_separate_party_account": 0,
"capital_work_in_progress_account": "CWIP Account - DL",
"chart_of_accounts": "Standard",
"company_description": null,
"company_logo": null,
"company_name": "Daniels Landscape Supplies",
"cost_center": "Main - DL",
"country": "United States",
"create_chart_of_accounts_based_on": "Standard Template",
"credit_limit": 0.0,
"date_of_commencement": null,
"date_of_establishment": null,
"date_of_incorporation": null,
"default_advance_paid_account": null,
"default_advance_received_account": null,
"default_bank_account": null,
"default_buying_terms": null,
"default_cash_account": "Cash - DL",
"default_currency": "USD",
"default_deferred_expense_account": null,
"default_deferred_revenue_account": null,
"default_discount_account": null,
"default_employee_advance_account": null,
"default_expense_account": "Cost of Goods Sold - DL",
"default_expense_claim_payable_account": "Creditors - DL",
"default_finance_book": null,
"default_holiday_list": null,
"default_in_transit_warehouse": null,
"default_income_account": "Sales - DL",
"default_inventory_account": "Stock In Hand - DL",
"default_letter_head": null,
"default_operating_cost_account": null,
"default_payable_account": "Creditors - DL",
"default_payroll_payable_account": null,
"default_provisional_account": null,
"default_receivable_account": "Debtors - DL",
"default_sales_contact": null,
"default_selling_terms": null,
"default_warehouse_for_sales_return": null,
"depreciation_cost_center": "Main - DL",
"depreciation_expense_account": "Depreciation - DL",
"disposal_account": "Gain/Loss on Asset Disposal - DL",
"docstatus": 0,
"doctype": "Company",
"domain": null,
"email": null,
"enable_perpetual_inventory": 1,
"enable_provisional_accounting_for_non_stock_items": 0,
"exception_budget_approver_role": null,
"exchange_gain_loss_account": "Exchange Gain/Loss - DL",
"existing_company": null,
"expenses_included_in_asset_valuation": "Expenses Included In Asset Valuation - DL",
"expenses_included_in_valuation": "Expenses Included In Valuation - DL",
"fax": null,
"is_group": 0,
"modified": "2026-02-15 00:56:31.935944",
"monthly_sales_target": 0.0,
"name": "Daniels Landscape Supplies",
"old_parent": "",
"parent_company": null,
"payment_terms": null,
"phone_no": null,
"reconcile_on_advance_payment_date": 0,
"reconciliation_takes_effect_on": "Oldest Of Invoice Or Advance",
"registration_details": null,
"round_off_account": "Round Off - DL",
"round_off_cost_center": "Main - DL",
"round_off_for_opening": null,
"sales_monthly_history": "{}",
"series_for_depreciation_entry": null,
"stock_adjustment_account": "Stock Adjustment - DL",
"stock_received_but_not_billed": "Stock Received But Not Billed - DL",
"submit_err_jv": 0,
"tax_id": null,
"total_monthly_sales": 0.0,
"transactions_annual_history": "{}",
"unrealized_exchange_gain_loss_account": null,
"unrealized_profit_loss_account": null,
"website": null,
"write_off_account": "Write Off - DL"
},
{
"abbr": "SD",
"accumulated_depreciation_account": "Accumulated Depreciation - SD",
"allow_account_creation_against_child_company": 0,
"asset_received_but_not_billed": "Asset Received But Not Billed - SD",
"auto_err_frequency": "Daily",
"auto_exchange_rate_revaluation": 0,
"book_advance_payments_in_separate_party_account": 0,
"capital_work_in_progress_account": "CWIP Account - SD",
"chart_of_accounts": "Standard",
"company_description": null,
"company_logo": null,
"company_name": "sprinklersnorthwest (Demo)",
"cost_center": "Main - SD",
"country": "United States",
"create_chart_of_accounts_based_on": "Standard Template",
"credit_limit": 0.0,
"date_of_commencement": null,
"date_of_establishment": null,
"date_of_incorporation": null,
"default_advance_paid_account": null,
"default_advance_received_account": null,
"default_bank_account": "Bank Account - SD",
"default_buying_terms": null,
"default_cash_account": "Cash - SD",
"default_currency": "USD",
"default_deferred_expense_account": null,
"default_deferred_revenue_account": null,
"default_discount_account": null,
"default_employee_advance_account": null,
"default_expense_account": "Cost of Goods Sold - SD",
"default_expense_claim_payable_account": "Creditors - SD",
"default_finance_book": null,
"default_holiday_list": null,
"default_in_transit_warehouse": null,
"default_income_account": "Sales - SD",
"default_inventory_account": "Stock In Hand - SD",
"default_letter_head": null,
"default_operating_cost_account": null,
"default_payable_account": "Creditors - SD",
"default_payroll_payable_account": null,
"default_provisional_account": null,
"default_receivable_account": "Debtors - SD",
"default_sales_contact": null,
"default_selling_terms": null,
"default_warehouse_for_sales_return": null,
"depreciation_cost_center": "Main - SD",
"depreciation_expense_account": "Depreciation - SD",
"disposal_account": "Gain/Loss on Asset Disposal - SD",
"docstatus": 0,
"doctype": "Company",
"domain": null,
"email": null,
"enable_perpetual_inventory": 1,
"enable_provisional_accounting_for_non_stock_items": 0,
"exception_budget_approver_role": null,
"exchange_gain_loss_account": "Exchange Gain/Loss - SD",
"existing_company": null,
"expenses_included_in_asset_valuation": "Expenses Included In Asset Valuation - SD",
"expenses_included_in_valuation": "Expenses Included In Valuation - SD",
"fax": null,
"is_group": 0,
"modified": "2026-02-15 00:56:31.938072",
"monthly_sales_target": 0.0,
"name": "sprinklersnorthwest (Demo)",
"old_parent": "",
"parent_company": null,
"payment_terms": null,
"phone_no": null,
"reconcile_on_advance_payment_date": 0,
"reconciliation_takes_effect_on": "Oldest Of Invoice Or Advance",
"registration_details": null,
"round_off_account": "Round Off - SD",
"round_off_cost_center": "Main - SD",
"round_off_for_opening": null,
"sales_monthly_history": "{}",
"series_for_depreciation_entry": null,
"stock_adjustment_account": "Stock Adjustment - SD",
"stock_received_but_not_billed": "Stock Received But Not Billed - SD",
"submit_err_jv": 0,
"tax_id": null,
"total_monthly_sales": 0.0,
"transactions_annual_history": "{}",
"unrealized_exchange_gain_loss_account": null,
"unrealized_profit_loss_account": null,
"website": null,
"write_off_account": "Write Off - SD"
},
{
"abbr": "NYC",
"accumulated_depreciation_account": "Accumulated Depreciation - NYC",
"allow_account_creation_against_child_company": 0,
"asset_received_but_not_billed": "Asset Received But Not Billed - NYC",
"auto_err_frequency": "Daily",
"auto_exchange_rate_revaluation": 0,
"book_advance_payments_in_separate_party_account": 1,
"capital_work_in_progress_account": "CWIP Account - NYC",
"chart_of_accounts": "Standard",
"company_description": null,
"company_logo": null,
"company_name": "Nuco Yard Care",
"cost_center": "Main - NYC",
"country": "United States",
"create_chart_of_accounts_based_on": "Standard Template",
"credit_limit": 0.0,
"date_of_commencement": null,
"date_of_establishment": null,
"date_of_incorporation": null,
"default_advance_paid_account": null,
"default_advance_received_account": null,
"default_bank_account": null,
"default_buying_terms": null,
"default_cash_account": "Cash - NYC",
"default_currency": "USD",
"default_deferred_expense_account": null,
"default_deferred_revenue_account": null,
"default_discount_account": null,
"default_employee_advance_account": null,
"default_expense_account": "Cost of Goods Sold - NYC",
"default_expense_claim_payable_account": "Creditors - NYC",
"default_finance_book": null,
"default_holiday_list": "Standard Holiday List",
"default_in_transit_warehouse": null,
"default_income_account": "Sales - NYC",
"default_inventory_account": "Stock In Hand - NYC",
"default_letter_head": null,
"default_operating_cost_account": null,
"default_payable_account": "Creditors - NYC",
"default_payroll_payable_account": null,
"default_provisional_account": null,
"default_receivable_account": "Debtors - NYC",
"default_sales_contact": null,
"default_selling_terms": null,
"default_warehouse_for_sales_return": null,
"depreciation_cost_center": "Main - NYC",
"depreciation_expense_account": "Depreciation - NYC",
"disposal_account": "Gain/Loss on Asset Disposal - NYC",
"docstatus": 0,
"doctype": "Company",
"domain": null,
"email": "operations@nucoyardcare.com",
"enable_perpetual_inventory": 1,
"enable_provisional_accounting_for_non_stock_items": 0,
"exception_budget_approver_role": null,
"exchange_gain_loss_account": "Exchange Gain/Loss - NYC",
"existing_company": null,
"expenses_included_in_asset_valuation": "Expenses Included In Asset Valuation - NYC",
"expenses_included_in_valuation": "Expenses Included In Valuation - NYC",
"fax": null,
"is_group": 0,
"modified": "2026-02-15 00:56:31.942129",
"monthly_sales_target": 0.0,
"name": "Nuco Yard Care",
"old_parent": "",
"parent_company": null,
"payment_terms": null,
"phone_no": "208-518-6032",
"reconcile_on_advance_payment_date": 0,
"reconciliation_takes_effect_on": "Oldest Of Invoice Or Advance",
"registration_details": null,
"round_off_account": "Round Off - NYC",
"round_off_cost_center": "Main - NYC",
"round_off_for_opening": null,
"sales_monthly_history": "{}",
"series_for_depreciation_entry": null,
"stock_adjustment_account": "Stock Adjustment - NYC",
"stock_received_but_not_billed": "Stock Received But Not Billed - NYC",
"submit_err_jv": 0,
"tax_id": null,
"total_monthly_sales": 0.0,
"transactions_annual_history": "{}",
"unrealized_exchange_gain_loss_account": null,
"unrealized_profit_loss_account": null,
"website": "www.nucoyardcare.com",
"write_off_account": "Write Off - NYC"
},
{
"abbr": "LF",
"accumulated_depreciation_account": "Accumulated Depreciation - LF",
"allow_account_creation_against_child_company": 0,
"asset_received_but_not_billed": "Asset Received But Not Billed - LF",
"auto_err_frequency": "Daily",
"auto_exchange_rate_revaluation": 0,
"book_advance_payments_in_separate_party_account": 0,
"capital_work_in_progress_account": "CWIP Account - LF",
"chart_of_accounts": "Standard",
"company_description": null,
"company_logo": null,
"company_name": "Lowe Fencing",
"cost_center": "Main - LF",
"country": "United States",
"create_chart_of_accounts_based_on": "Standard Template",
"credit_limit": 0.0,
"date_of_commencement": null,
"date_of_establishment": null,
"date_of_incorporation": null,
"default_advance_paid_account": null,
"default_advance_received_account": null,
"default_bank_account": null,
"default_buying_terms": null,
"default_cash_account": "Cash - LF",
"default_currency": "USD",
"default_deferred_expense_account": null,
"default_deferred_revenue_account": null,
"default_discount_account": null,
"default_employee_advance_account": null,
"default_expense_account": "Cost of Goods Sold - LF",
"default_expense_claim_payable_account": "Creditors - LF",
"default_finance_book": null,
"default_holiday_list": "Standard Holiday List",
"default_in_transit_warehouse": null,
"default_income_account": "Fencing Sales - LF",
"default_inventory_account": "Stock In Hand - LF",
"default_letter_head": "Lowe Fencing",
"default_operating_cost_account": null,
"default_payable_account": "Creditors - LF",
"default_payroll_payable_account": null,
"default_provisional_account": null,
"default_receivable_account": "Debtors - LF",
"default_sales_contact": null,
"default_selling_terms": null,
"default_warehouse_for_sales_return": null,
"depreciation_cost_center": "Main - LF",
"depreciation_expense_account": "Depreciation - LF",
"disposal_account": "Gain/Loss on Asset Disposal - LF",
"docstatus": 0,
"doctype": "Company",
"domain": null,
"email": "office@lowefencing.com",
"enable_perpetual_inventory": 1,
"enable_provisional_accounting_for_non_stock_items": 0,
"exception_budget_approver_role": null,
"exchange_gain_loss_account": "Exchange Gain/Loss - LF",
"existing_company": null,
"expenses_included_in_asset_valuation": "Expenses Included In Asset Valuation - LF",
"expenses_included_in_valuation": "Expenses Included In Valuation - LF",
"fax": null,
"is_group": 0,
"modified": "2026-02-15 00:56:31.940118",
"monthly_sales_target": 0.0,
"name": "Lowe Fencing",
"old_parent": "",
"parent_company": null,
"payment_terms": null,
"phone_no": "2084848165",
"reconcile_on_advance_payment_date": 0,
"reconciliation_takes_effect_on": "Oldest Of Invoice Or Advance",
"registration_details": null,
"round_off_account": "Round Off - LF",
"round_off_cost_center": "Main - LF",
"round_off_for_opening": null,
"sales_monthly_history": "{}",
"series_for_depreciation_entry": null,
"stock_adjustment_account": "Stock Adjustment - LF",
"stock_received_but_not_billed": "Stock Received But Not Billed - LF",
"submit_err_jv": 0,
"tax_id": "81-1640506",
"total_monthly_sales": 0.0,
"transactions_annual_history": "{}",
"unrealized_exchange_gain_loss_account": null,
"unrealized_profit_loss_account": null,
"website": null,
"write_off_account": "Write Off - LF"
},
{
"abbr": "S",
"accumulated_depreciation_account": "Accumulated Depreciation - S",
"allow_account_creation_against_child_company": 0,
"asset_received_but_not_billed": "Asset Received But Not Billed - S",
"auto_err_frequency": "Daily",
"auto_exchange_rate_revaluation": 0,
"book_advance_payments_in_separate_party_account": 1,
"capital_work_in_progress_account": "CWIP Account - S",
"chart_of_accounts": "Standard",
"company_description": null,
"company_logo": null,
"company_name": "Sprinklers Northwest",
"cost_center": "Main - S",
"country": "United States",
"create_chart_of_accounts_based_on": "Standard Template",
"credit_limit": 0.0,
"date_of_commencement": null,
"date_of_establishment": null,
"date_of_incorporation": "2009-04-06",
"default_advance_paid_account": null,
"default_advance_received_account": "Customer Deposits - S",
"default_bank_account": "Undeposited Funds - S",
"default_buying_terms": null,
"default_cash_account": "Undeposited Funds - S",
"default_currency": "USD",
"default_deferred_expense_account": null,
"default_deferred_revenue_account": null,
"default_discount_account": null,
"default_employee_advance_account": "Employee Advances - S",
"default_expense_account": "Cost of Goods Sold - S",
"default_expense_claim_payable_account": "Creditors - S",
"default_finance_book": null,
"default_holiday_list": "Standard Holiday List",
"default_in_transit_warehouse": null,
"default_income_account": "Sales - S",
"default_inventory_account": "Stock In Hand - S",
"default_letter_head": "Sprinklers Northwest",
"default_operating_cost_account": null,
"default_payable_account": "Creditors - S",
"default_payroll_payable_account": "Payroll Payable - S",
"default_provisional_account": null,
"default_receivable_account": "Debtors - S",
"default_sales_contact": null,
"default_selling_terms": null,
"default_warehouse_for_sales_return": null,
"depreciation_cost_center": "Main - S",
"depreciation_expense_account": "Depreciation - S",
"disposal_account": "Gain/Loss on Asset Disposal - S",
"docstatus": 0,
"doctype": "Company",
"domain": "",
"email": "info@sprinklersnorthwest.com",
"enable_perpetual_inventory": 1,
"enable_provisional_accounting_for_non_stock_items": 0,
"exception_budget_approver_role": null,
"exchange_gain_loss_account": "Exchange Gain/Loss - S",
"existing_company": null,
"expenses_included_in_asset_valuation": "Expenses Included In Asset Valuation - S",
"expenses_included_in_valuation": "Expenses Included In Valuation - S",
"fax": null,
"is_group": 0,
"modified": "2026-02-15 00:56:31.946270",
"monthly_sales_target": 0.0,
"name": "Sprinklers Northwest",
"old_parent": "",
"parent_company": null,
"payment_terms": null,
"phone_no": "208-818-8838",
"reconcile_on_advance_payment_date": 0,
"reconciliation_takes_effect_on": "Oldest Of Invoice Or Advance",
"registration_details": null,
"round_off_account": "Round Off - S",
"round_off_cost_center": "Main - S",
"round_off_for_opening": null,
"sales_monthly_history": "{\"02-2025\": 0.0, \"02-2026\": 0.0, \"05-2025\": 0.0, \"07-2025\": 0.0}",
"series_for_depreciation_entry": null,
"stock_adjustment_account": "Stock Adjustment - S",
"stock_received_but_not_billed": "Stock Received But Not Billed - S",
"submit_err_jv": 0,
"tax_id": "26-4603792",
"total_monthly_sales": 23400.0,
"transactions_annual_history": "{\"1740463200.0\": 1, \"1740549600.0\": 1, \"1741154400.0\": 1, \"1744866000.0\": 1, \"1744952400.0\": 1, \"1745557200.0\": 3, \"1746162000.0\": 1, \"1746594000.0\": 1, \"1746680400.0\": 2, \"1746853200.0\": 1, \"1747285200.0\": 1, \"1748581200.0\": 1, \"1750136400.0\": 2, \"1753333200.0\": 1, \"1755234000.0\": 2, \"1755493200.0\": 1, \"1755752400.0\": 1, \"1756270800.0\": 1, \"1756357200.0\": 1, \"1759986000.0\": 1, \"1764568800.0\": 2, \"1764655200.0\": 5, \"1765260000.0\": 7, \"1765778400.0\": 1, \"1766124000.0\": 1, \"1766210400.0\": 1, \"1766469600.0\": 13, \"1766728800.0\": 6, \"1767938400.0\": 1, \"1768456800.0\": 20, \"1768543200.0\": 1, \"1768975200.0\": 1, \"1769148000.0\": 1, \"1769407200.0\": 1, \"1769493600.0\": 1, \"1770184800.0\": 1, \"1770357600.0\": 1, \"1770444000.0\": 1, \"1770530400.0\": 1, \"1770616800.0\": 1, \"1770789600.0\": 1, \"1770876000.0\": 1, \"1770962400.0\": 1, \"1771048800.0\": 1}",
"unrealized_exchange_gain_loss_account": null,
"unrealized_profit_loss_account": null,
"website": "www.sprinklersnorthwest.com",
"write_off_account": "Write Off - S"
}
]

View file

@ -1,158 +0,0 @@
[
{
"company": "sprinklersnorthwest (Demo)",
"cost_center_name": "sprinklersnorthwest (Demo)",
"cost_center_number": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Cost Center",
"is_group": 1,
"modified": "2024-04-03 13:53:36.319170",
"name": "sprinklersnorthwest (Demo) - SD",
"old_parent": "",
"parent_cost_center": null
},
{
"company": "Nuco Yard Care",
"cost_center_name": "Nuco Yard Care",
"cost_center_number": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Cost Center",
"is_group": 1,
"modified": "2024-04-08 14:26:26.835628",
"name": "Nuco Yard Care - NYC",
"old_parent": "",
"parent_cost_center": null
},
{
"company": "Veritas Stone",
"cost_center_name": "Veritas Stone",
"cost_center_number": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Cost Center",
"is_group": 1,
"modified": "2024-04-12 04:46:43.619995",
"name": "Veritas Stone - VS",
"old_parent": "",
"parent_cost_center": null
},
{
"company": "Daniels Landscape Supplies",
"cost_center_name": "Daniels Landscape Supplies",
"cost_center_number": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Cost Center",
"is_group": 1,
"modified": "2024-04-12 05:00:21.971732",
"name": "Daniels Landscape Supplies - DL",
"old_parent": "",
"parent_cost_center": null
},
{
"company": "Lowe Fencing",
"cost_center_name": "Lowe Fencing",
"cost_center_number": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Cost Center",
"is_group": 1,
"modified": "2024-04-08 14:26:52.065488",
"name": "Lowe Fencing - LF",
"old_parent": "",
"parent_cost_center": null
},
{
"company": "Sprinklers Northwest",
"cost_center_name": "sprinklersnorthwest",
"cost_center_number": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Cost Center",
"is_group": 1,
"modified": "2024-04-03 13:53:07.596849",
"name": "sprinklersnorthwest - S",
"old_parent": "",
"parent_cost_center": null
},
{
"company": "Veritas Stone",
"cost_center_name": "Main",
"cost_center_number": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Cost Center",
"is_group": 0,
"modified": "2024-04-12 04:46:43.636132",
"name": "Main - VS",
"old_parent": "Veritas Stone - VS",
"parent_cost_center": "Veritas Stone - VS"
},
{
"company": "Nuco Yard Care",
"cost_center_name": "Main",
"cost_center_number": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Cost Center",
"is_group": 0,
"modified": "2024-04-08 14:26:26.857578",
"name": "Main - NYC",
"old_parent": "Nuco Yard Care - NYC",
"parent_cost_center": "Nuco Yard Care - NYC"
},
{
"company": "Daniels Landscape Supplies",
"cost_center_name": "Main",
"cost_center_number": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Cost Center",
"is_group": 0,
"modified": "2024-04-12 05:00:22.025686",
"name": "Main - DL",
"old_parent": "Daniels Landscape Supplies - DL",
"parent_cost_center": "Daniels Landscape Supplies - DL"
},
{
"company": "sprinklersnorthwest (Demo)",
"cost_center_name": "Main",
"cost_center_number": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Cost Center",
"is_group": 0,
"modified": "2024-04-03 13:53:36.354903",
"name": "Main - SD",
"old_parent": "sprinklersnorthwest (Demo) - SD",
"parent_cost_center": "sprinklersnorthwest (Demo) - SD"
},
{
"company": "Lowe Fencing",
"cost_center_name": "Main",
"cost_center_number": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Cost Center",
"is_group": 0,
"modified": "2024-04-08 14:26:52.096499",
"name": "Main - LF",
"old_parent": "Lowe Fencing - LF",
"parent_cost_center": "Lowe Fencing - LF"
},
{
"company": "Sprinklers Northwest",
"cost_center_name": "Main",
"cost_center_number": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Cost Center",
"is_group": 0,
"modified": "2024-04-03 13:53:07.616694",
"name": "Main - S",
"old_parent": "sprinklersnorthwest - S",
"parent_cost_center": "sprinklersnorthwest - S"
}
]

View file

@ -774,7 +774,7 @@
"length": 0, "length": 0,
"link_filters": null, "link_filters": null,
"mandatory_depends_on": null, "mandatory_depends_on": null,
"modified": "2026-02-13 03:40:47.846272", "modified": "2026-02-12 02:52:42.039792",
"module": null, "module": null,
"name": "Quotation-requires_half_payment", "name": "Quotation-requires_half_payment",
"no_copy": 0, "no_copy": 0,
@ -2199,7 +2199,7 @@
"length": 0, "length": 0,
"link_filters": null, "link_filters": null,
"mandatory_depends_on": null, "mandatory_depends_on": null,
"modified": "2026-02-13 03:40:47.954343", "modified": "2026-02-12 02:52:42.142425",
"module": null, "module": null,
"name": "Sales Order-requires_half_payment", "name": "Sales Order-requires_half_payment",
"no_copy": 0, "no_copy": 0,
@ -8070,7 +8070,7 @@
"length": 0, "length": 0,
"link_filters": null, "link_filters": null,
"mandatory_depends_on": null, "mandatory_depends_on": null,
"modified": "2026-02-13 03:40:48.116290", "modified": "2026-02-12 04:10:06.712703",
"module": null, "module": null,
"name": "Project-requires_half_payment", "name": "Project-requires_half_payment",
"no_copy": 0, "no_copy": 0,
@ -8469,7 +8469,7 @@
"length": 0, "length": 0,
"link_filters": null, "link_filters": null,
"mandatory_depends_on": null, "mandatory_depends_on": null,
"modified": "2026-02-13 03:40:48.203042", "modified": "2026-02-12 04:10:06.808397",
"module": null, "module": null,
"name": "Project-is_half_down_paid", "name": "Project-is_half_down_paid",
"no_copy": 0, "no_copy": 0,
@ -8754,7 +8754,7 @@
"length": 0, "length": 0,
"link_filters": null, "link_filters": null,
"mandatory_depends_on": null, "mandatory_depends_on": null,
"modified": "2026-02-13 03:40:48.044130", "modified": "2026-02-12 04:10:06.643135",
"module": null, "module": null,
"name": "Project-is_scheduled", "name": "Project-is_scheduled",
"no_copy": 0, "no_copy": 0,
@ -10179,7 +10179,7 @@
"length": 0, "length": 0,
"link_filters": null, "link_filters": null,
"mandatory_depends_on": null, "mandatory_depends_on": null,
"modified": "2026-02-13 03:40:47.644900", "modified": "2026-02-12 04:10:06.196780",
"module": null, "module": null,
"name": "Address-latitude", "name": "Address-latitude",
"no_copy": 0, "no_copy": 0,
@ -10293,7 +10293,7 @@
"length": 0, "length": 0,
"link_filters": null, "link_filters": null,
"mandatory_depends_on": null, "mandatory_depends_on": null,
"modified": "2026-02-13 03:40:47.742672", "modified": "2026-02-12 04:10:06.320979",
"module": null, "module": null,
"name": "Address-longitude", "name": "Address-longitude",
"no_copy": 0, "no_copy": 0,
@ -13964,6 +13964,63 @@
"unique": 0, "unique": 0,
"width": null "width": null
}, },
{
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"collapsible_depends_on": null,
"columns": 0,
"default": null,
"depends_on": "eval:doc.accept_payment && !doc.amount_based_on_field",
"description": null,
"docstatus": 0,
"doctype": "Custom Field",
"dt": "Web Form",
"fetch_from": null,
"fetch_if_empty": 0,
"fieldname": "amount",
"fieldtype": "Currency",
"hidden": 0,
"hide_border": 0,
"hide_days": 0,
"hide_seconds": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_preview": 0,
"in_standard_filter": 0,
"insert_after": "amount_field",
"is_system_generated": 1,
"is_virtual": 0,
"label": "Amount",
"length": 0,
"link_filters": null,
"mandatory_depends_on": null,
"modified": "2026-01-27 11:11:05.387203",
"module": null,
"name": "Web Form-amount",
"no_copy": 0,
"non_negative": 0,
"options": null,
"permlevel": 0,
"placeholder": null,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": null,
"read_only": 0,
"read_only_depends_on": null,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"show_dashboard": 0,
"sort_options": 0,
"translatable": 0,
"unique": 0,
"width": null
},
{ {
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
@ -14135,63 +14192,6 @@
"unique": 0, "unique": 0,
"width": null "width": null
}, },
{
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"collapsible_depends_on": null,
"columns": 0,
"default": null,
"depends_on": "eval:doc.accept_payment && !doc.amount_based_on_field",
"description": null,
"docstatus": 0,
"doctype": "Custom Field",
"dt": "Web Form",
"fetch_from": null,
"fetch_if_empty": 0,
"fieldname": "amount",
"fieldtype": "Currency",
"hidden": 0,
"hide_border": 0,
"hide_days": 0,
"hide_seconds": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_preview": 0,
"in_standard_filter": 0,
"insert_after": "amount_field",
"is_system_generated": 1,
"is_virtual": 0,
"label": "Amount",
"length": 0,
"link_filters": null,
"mandatory_depends_on": null,
"modified": "2026-01-27 11:11:05.387203",
"module": null,
"name": "Web Form-amount",
"no_copy": 0,
"non_negative": 0,
"options": null,
"permlevel": 0,
"placeholder": null,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": null,
"read_only": 0,
"read_only_depends_on": null,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"show_dashboard": 0,
"sort_options": 0,
"translatable": 0,
"unique": 0,
"width": null
},
{ {
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,
@ -16016,63 +16016,6 @@
"unique": 0, "unique": 0,
"width": null "width": null
}, },
{
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"collapsible_depends_on": null,
"columns": 0,
"default": null,
"depends_on": null,
"description": null,
"docstatus": 0,
"doctype": "Custom Field",
"dt": "Quotation",
"fetch_from": null,
"fetch_if_empty": 0,
"fieldname": "remarks",
"fieldtype": "Small Text",
"hidden": 0,
"hide_border": 0,
"hide_days": 0,
"hide_seconds": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_preview": 0,
"in_standard_filter": 0,
"insert_after": "grand_total",
"is_system_generated": 1,
"is_virtual": 0,
"label": "Remarks",
"length": 0,
"link_filters": null,
"mandatory_depends_on": null,
"modified": "2026-02-13 03:40:47.513866",
"module": null,
"name": "Quotation-remarks",
"no_copy": 0,
"non_negative": 0,
"options": null,
"permlevel": 0,
"placeholder": null,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"print_width": null,
"read_only": 0,
"read_only_depends_on": null,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"show_dashboard": 0,
"sort_options": 0,
"translatable": 0,
"unique": 0,
"width": null
},
{ {
"allow_in_quick_entry": 0, "allow_in_quick_entry": 0,
"allow_on_submit": 0, "allow_on_submit": 0,

File diff suppressed because it is too large Load diff

View file

@ -1,41 +0,0 @@
[
{
"auto_created": 0,
"companies": [],
"disabled": 0,
"docstatus": 0,
"doctype": "Fiscal Year",
"is_short_year": 0,
"modified": "2026-02-04 12:09:37.726400",
"name": "2026",
"year": "2026",
"year_end_date": "2026-12-31",
"year_start_date": "2026-01-01"
},
{
"auto_created": 0,
"companies": [],
"disabled": 0,
"docstatus": 0,
"doctype": "Fiscal Year",
"is_short_year": 0,
"modified": "2024-04-03 13:53:06.521863",
"name": "2024",
"year": "2024",
"year_end_date": "2024-12-31",
"year_start_date": "2024-01-01"
},
{
"auto_created": 1,
"companies": [],
"disabled": 0,
"docstatus": 0,
"doctype": "Fiscal Year",
"is_short_year": 0,
"modified": "2024-12-28 00:01:04.314401",
"name": "2025",
"year": "2025",
"year_end_date": "2025-12-31",
"year_start_date": "2025-01-01"
}
]

File diff suppressed because it is too large Load diff

View file

@ -1,72 +0,0 @@
[
{
"bid_meeting_note_form": "SNW Install Bid Meeting Notes",
"calendar_color": "#CB2929",
"company": "Sprinklers Northwest",
"custom__complete_method": "Task Weight",
"docstatus": 0,
"doctype": "Project Template",
"item_groups": "SNW-I, SNW-S, SNW-LS",
"modified": "2026-02-15 01:31:39.325004",
"name": "SNW Install",
"project_type": "External",
"tasks": [
{
"parent": "SNW Install",
"parentfield": "tasks",
"parenttype": "Project Template",
"subject": "Send customer 3-5 day window for start date",
"task": "TASK-2025-00001"
},
{
"parent": "SNW Install",
"parentfield": "tasks",
"parenttype": "Project Template",
"subject": "811/Locate call in",
"task": "TASK-2025-00002"
},
{
"parent": "SNW Install",
"parentfield": "tasks",
"parenttype": "Project Template",
"subject": "Permit(s) call in and pay",
"task": "TASK-2025-00003"
},
{
"parent": "SNW Install",
"parentfield": "tasks",
"parenttype": "Project Template",
"subject": "Primary Job",
"task": "TASK-2025-00004"
},
{
"parent": "SNW Install",
"parentfield": "tasks",
"parenttype": "Project Template",
"subject": "Hydroseeding",
"task": "TASK-2025-00005"
},
{
"parent": "SNW Install",
"parentfield": "tasks",
"parenttype": "Project Template",
"subject": "Curbing",
"task": "TASK-2025-00006"
},
{
"parent": "SNW Install",
"parentfield": "tasks",
"parenttype": "Project Template",
"subject": "15-Day QA",
"task": "TASK-2025-00007"
},
{
"parent": "SNW Install",
"parentfield": "tasks",
"parenttype": "Project Template",
"subject": "Permit Close-out",
"task": "TASK-2025-00008"
}
]
}
]

View file

@ -269,51 +269,6 @@
"total_expense_claim": 0.0, "total_expense_claim": 0.0,
"type": "Admin" "type": "Admin"
}, },
{
"act_end_date": null,
"act_start_date": null,
"actual_time": 0.0,
"closing_date": null,
"color": null,
"company": "Sprinklers Northwest",
"completed_by": null,
"completed_on": null,
"custom_foreman": "HR-EMP-00014",
"custom_property": null,
"customer": null,
"department": null,
"depends_on": [],
"depends_on_tasks": "",
"description": null,
"docstatus": 0,
"doctype": "Task",
"duration": 0,
"exp_end_date": null,
"exp_start_date": null,
"expected_time": 0.0,
"is_group": 0,
"is_milestone": 0,
"is_template": 1,
"issue": null,
"modified": "2026-01-23 02:29:45.172285",
"name": "TASK-2025-00007",
"old_parent": "",
"parent_task": null,
"priority": "Low",
"progress": 0.0,
"project": null,
"project_template": null,
"review_date": null,
"start": 0,
"status": "Template",
"subject": "15-Day QA",
"task_weight": 0.0,
"template_task": null,
"total_billing_amount": 0.0,
"total_costing_amount": 0.0,
"total_expense_claim": 0.0,
"type": "15 Day Warranty Follow-Up"
},
{ {
"act_end_date": null, "act_end_date": null,
"act_start_date": null, "act_start_date": null,
@ -358,5 +313,50 @@
"total_costing_amount": 0.0, "total_costing_amount": 0.0,
"total_expense_claim": 0.0, "total_expense_claim": 0.0,
"type": "Main Job" "type": "Main Job"
},
{
"act_end_date": null,
"act_start_date": null,
"actual_time": 0.0,
"closing_date": null,
"color": null,
"company": "Sprinklers Northwest",
"completed_by": null,
"completed_on": null,
"custom_foreman": "HR-EMP-00014",
"custom_property": null,
"customer": null,
"department": null,
"depends_on": [],
"depends_on_tasks": "",
"description": null,
"docstatus": 0,
"doctype": "Task",
"duration": 0,
"exp_end_date": null,
"exp_start_date": null,
"expected_time": 0.0,
"is_group": 0,
"is_milestone": 0,
"is_template": 1,
"issue": null,
"modified": "2026-01-23 02:29:45.172285",
"name": "TASK-2025-00007",
"old_parent": "",
"parent_task": null,
"priority": "Low",
"progress": 0.0,
"project": null,
"project_template": null,
"review_date": null,
"start": 0,
"status": "Template",
"subject": "15-Day QA",
"task_weight": 0.0,
"template_task": null,
"total_billing_amount": 0.0,
"total_costing_amount": 0.0,
"total_expense_claim": 0.0,
"type": "15 Day Warranty Follow-Up"
} }
] ]

View file

@ -1,527 +0,0 @@
[
{
"base_date": "Start",
"calculate_from": "Project",
"custom_completion_trigger": null,
"custom_completion_trigger_doctype": null,
"custom_target_percent": 0,
"days": 0,
"description": "Collect half down payment on project creation.",
"docstatus": 0,
"doctype": "Task Type",
"logic_key": null,
"modified": "2026-01-26 12:59:50.869932",
"name": "1/2 Down Payment",
"no_due_date": 0,
"offset_days": 0,
"offset_direction": "Before",
"skip_holidays": 1,
"skip_weekends": 0,
"task_type_calculate_from": null,
"title": "1/2 Down Payment",
"trigger": "Created",
"triggering_doctype": "Project",
"weight": 0.0,
"work_type": "Admin"
},
{
"base_date": "Start",
"calculate_from": "Service Address 2",
"custom_completion_trigger": null,
"custom_completion_trigger_doctype": null,
"custom_target_percent": 0,
"days": 0,
"description": "Stage machinery one day before installation start.",
"docstatus": 0,
"doctype": "Task Type",
"logic_key": null,
"modified": "2026-01-26 13:00:47.389623",
"name": "Machine Staging",
"no_due_date": 0,
"offset_days": 1,
"offset_direction": "Before",
"skip_holidays": 1,
"skip_weekends": 0,
"task_type_calculate_from": null,
"title": "Machine Staging",
"trigger": "Scheduled",
"triggering_doctype": "Service Address 2",
"weight": 0.0,
"work_type": "Admin"
},
{
"base_date": "Completion",
"calculate_from": "Service Address 2",
"custom_completion_trigger": null,
"custom_completion_trigger_doctype": null,
"custom_target_percent": 0,
"days": 0,
"description": "Send final invoice within 5 days of job completion.",
"docstatus": 0,
"doctype": "Task Type",
"logic_key": null,
"modified": "2026-01-26 13:01:14.573788",
"name": "Final Invoice",
"no_due_date": 0,
"offset_days": 5,
"offset_direction": "After",
"skip_holidays": 1,
"skip_weekends": 0,
"task_type_calculate_from": null,
"title": "Final Invoice",
"trigger": "Completed",
"triggering_doctype": "Service Address 2",
"weight": 0.0,
"work_type": "Admin"
},
{
"base_date": "Completion",
"calculate_from": "Service Address 2",
"custom_completion_trigger": null,
"custom_completion_trigger_doctype": null,
"custom_target_percent": 0,
"days": 0,
"description": "Backflow test after job completion if quoted.",
"docstatus": 0,
"doctype": "Task Type",
"logic_key": null,
"modified": "2026-01-26 13:01:34.781732",
"name": "Backflow Test",
"no_due_date": 0,
"offset_days": 0,
"offset_direction": "After",
"skip_holidays": 1,
"skip_weekends": 0,
"task_type_calculate_from": null,
"title": "Backflow Test",
"trigger": "Completed",
"triggering_doctype": "Service Address 2",
"weight": 0.0,
"work_type": "Admin"
},
{
"base_date": "Completion",
"calculate_from": "Service Address 2",
"custom_completion_trigger": null,
"custom_completion_trigger_doctype": null,
"custom_target_percent": 0,
"days": 0,
"description": "Schedule permit inspection 5 days after completion.",
"docstatus": 0,
"doctype": "Task Type",
"logic_key": null,
"modified": "2026-01-26 13:01:44.550215",
"name": "Schedule Permit Inspection",
"no_due_date": 0,
"offset_days": 5,
"offset_direction": "After",
"skip_holidays": 1,
"skip_weekends": 0,
"task_type_calculate_from": null,
"title": "Schedule Permit Inspection",
"trigger": "Completed",
"triggering_doctype": "Service Address 2",
"weight": 0.0,
"work_type": "Admin"
},
{
"base_date": "Completion",
"calculate_from": "Service Address 2",
"custom_completion_trigger": null,
"custom_completion_trigger_doctype": null,
"custom_target_percent": 0,
"days": 0,
"description": "30-day warranty check after completion.",
"docstatus": 0,
"doctype": "Task Type",
"logic_key": null,
"modified": "2026-01-26 13:02:08.165742",
"name": "30 Day Warranty Check",
"no_due_date": 0,
"offset_days": 30,
"offset_direction": "After",
"skip_holidays": 1,
"skip_weekends": 0,
"task_type_calculate_from": null,
"title": "30 Day Warranty Check",
"trigger": "Completed",
"triggering_doctype": "Service Address 2",
"weight": 0.0,
"work_type": "Admin"
},
{
"base_date": "Completion",
"calculate_from": "Service Address 2",
"custom_completion_trigger": null,
"custom_completion_trigger_doctype": null,
"custom_target_percent": 0,
"days": 0,
"description": "Payment reminder sent 30 days after completion.",
"docstatus": 0,
"doctype": "Task Type",
"logic_key": null,
"modified": "2026-01-26 13:02:21.758218",
"name": "30 Day Payment Reminder",
"no_due_date": 0,
"offset_days": 30,
"offset_direction": "After",
"skip_holidays": 1,
"skip_weekends": 0,
"task_type_calculate_from": null,
"title": "30 Day Payment Reminder",
"trigger": "Completed",
"triggering_doctype": "Service Address 2",
"weight": 0.0,
"work_type": "Admin"
},
{
"base_date": "Completion",
"calculate_from": "Service Address 2",
"custom_completion_trigger": null,
"custom_completion_trigger_doctype": null,
"custom_target_percent": 0,
"days": 0,
"description": "Late payment notification at 60 days post completion.",
"docstatus": 0,
"doctype": "Task Type",
"logic_key": null,
"modified": "2026-01-26 13:02:33.693892",
"name": "60 Day Late Payment Notice",
"no_due_date": 0,
"offset_days": 60,
"offset_direction": "After",
"skip_holidays": 1,
"skip_weekends": 0,
"task_type_calculate_from": null,
"title": "60 Day Late Payment Notice",
"trigger": "Completed",
"triggering_doctype": "Service Address 2",
"weight": 0.0,
"work_type": "Admin"
},
{
"base_date": "Completion",
"calculate_from": "Service Address 2",
"custom_completion_trigger": null,
"custom_completion_trigger_doctype": null,
"custom_target_percent": 0,
"days": 0,
"description": "Lien notice if payment is still late after 80 days.",
"docstatus": 0,
"doctype": "Task Type",
"logic_key": null,
"modified": "2026-01-26 13:02:42.742371",
"name": "80 Day Lien Notice",
"no_due_date": 0,
"offset_days": 80,
"offset_direction": "After",
"skip_holidays": 1,
"skip_weekends": 0,
"task_type_calculate_from": null,
"title": "80 Day Lien Notice",
"trigger": "Completed",
"triggering_doctype": "Service Address 2",
"weight": 0.0,
"work_type": "Admin"
},
{
"base_date": "Completion",
"calculate_from": "Service Address 2",
"custom_completion_trigger": null,
"custom_completion_trigger_doctype": null,
"custom_target_percent": 0,
"days": 0,
"description": "One-year warranty call or walk-through.",
"docstatus": 0,
"doctype": "Task Type",
"logic_key": null,
"modified": "2026-01-26 13:02:51.999530",
"name": "365 Day Warranty Call / Walk",
"no_due_date": 0,
"offset_days": 365,
"offset_direction": "After",
"skip_holidays": 1,
"skip_weekends": 0,
"task_type_calculate_from": null,
"title": "365 Day Warranty Call / Walk",
"trigger": "Completed",
"triggering_doctype": "Service Address 2",
"weight": 0.0,
"work_type": "Admin"
},
{
"base_date": "Start",
"calculate_from": "Service Address 2",
"custom_completion_trigger": null,
"custom_completion_trigger_doctype": null,
"custom_target_percent": 0,
"days": 0,
"description": "Locate utilities for digging",
"docstatus": 0,
"doctype": "Task Type",
"logic_key": null,
"modified": "2026-01-26 13:00:26.110307",
"name": "Locate",
"no_due_date": 0,
"offset_days": 7,
"offset_direction": "Before",
"skip_holidays": 1,
"skip_weekends": 0,
"task_type_calculate_from": null,
"title": "Locate",
"trigger": "Scheduled",
"triggering_doctype": "Service Address 2",
"weight": 0.0,
"work_type": "Admin"
},
{
"base_date": "Start",
"calculate_from": "Service Address 2",
"custom_completion_trigger": null,
"custom_completion_trigger_doctype": null,
"custom_target_percent": 0,
"days": 0,
"description": "Utility locate request prior to installation start.",
"docstatus": 0,
"doctype": "Task Type",
"logic_key": null,
"modified": "2026-02-08 01:46:40.122526",
"name": "811/Locate",
"no_due_date": 0,
"offset_days": 7,
"offset_direction": "Before",
"skip_holidays": 1,
"skip_weekends": 0,
"task_type_calculate_from": null,
"title": "811/Locate",
"trigger": "Scheduled",
"triggering_doctype": "Service Address 2",
"weight": 7.0,
"work_type": "Admin"
},
{
"base_date": "Project Start",
"calculate_from": "Service Appointment",
"custom_completion_trigger": null,
"custom_completion_trigger_doctype": null,
"custom_target_percent": 0,
"days": 0,
"description": null,
"docstatus": 0,
"doctype": "Task Type",
"logic_key": null,
"modified": "2024-12-20 16:48:23.131743",
"name": "Topshot",
"no_due_date": 0,
"offset_days": 7,
"offset_direction": "Before",
"skip_holidays": 1,
"skip_weekends": 1,
"task_type_calculate_from": null,
"title": null,
"trigger": null,
"triggering_doctype": "Service Address 2",
"weight": 0.0,
"work_type": "Admin"
},
{
"base_date": "Start",
"calculate_from": "Service Address 2",
"custom_completion_trigger": null,
"custom_completion_trigger_doctype": null,
"custom_target_percent": 0,
"days": 0,
"description": "Permits required prior to installation start.",
"docstatus": 0,
"doctype": "Task Type",
"logic_key": null,
"modified": "2026-02-08 01:48:15.012387",
"name": "Permit",
"no_due_date": 0,
"offset_days": 7,
"offset_direction": "Before",
"skip_holidays": 1,
"skip_weekends": 0,
"task_type_calculate_from": null,
"title": "Permit",
"trigger": "Scheduled",
"triggering_doctype": "Service Address 2",
"weight": 7.0,
"work_type": "Admin"
},
{
"base_date": "Completion",
"calculate_from": "Service Address 2",
"custom_completion_trigger": null,
"custom_completion_trigger_doctype": null,
"custom_target_percent": 0,
"days": 0,
"description": "15-day warranty follow-up after completion.",
"docstatus": 0,
"doctype": "Task Type",
"logic_key": null,
"modified": "2026-01-26 13:01:56.949793",
"name": "15 Day Warranty Follow-Up",
"no_due_date": 0,
"offset_days": 15,
"offset_direction": "After",
"skip_holidays": 1,
"skip_weekends": 0,
"task_type_calculate_from": null,
"title": "15 Day Warranty Follow-Up",
"trigger": "Completed",
"triggering_doctype": "Service Address 2",
"weight": 0.0,
"work_type": "Admin"
},
{
"base_date": "Project Start",
"calculate_from": "Service Appointment",
"custom_completion_trigger": null,
"custom_completion_trigger_doctype": null,
"custom_target_percent": 0,
"days": 0,
"description": null,
"docstatus": 0,
"doctype": "Task Type",
"logic_key": null,
"modified": "2024-12-17 14:18:26.429960",
"name": "Subcontractor",
"no_due_date": 0,
"offset_days": 7,
"offset_direction": "Before",
"skip_holidays": 1,
"skip_weekends": 1,
"task_type_calculate_from": null,
"title": null,
"trigger": null,
"triggering_doctype": "Service Address 2",
"weight": 0.0,
"work_type": "Admin"
},
{
"base_date": "End",
"calculate_from": "Service Address 2",
"custom_completion_trigger": "Completed",
"custom_completion_trigger_doctype": "Service Address 2",
"custom_target_percent": 0,
"days": 0,
"description": "Task tracking for the main service job.",
"docstatus": 0,
"doctype": "Task Type",
"logic_key": null,
"modified": "2026-02-08 02:35:42.343305",
"name": "Main Job",
"no_due_date": 0,
"offset_days": 0,
"offset_direction": "After",
"skip_holidays": 1,
"skip_weekends": 0,
"task_type_calculate_from": null,
"title": "Main Job",
"trigger": "Scheduled",
"triggering_doctype": "Service Address 2",
"weight": 25.0,
"work_type": "Labor"
},
{
"base_date": "Project Start",
"calculate_from": "Service Appointment",
"custom_completion_trigger": null,
"custom_completion_trigger_doctype": null,
"custom_target_percent": 0,
"days": 0,
"description": null,
"docstatus": 0,
"doctype": "Task Type",
"logic_key": null,
"modified": "2025-05-10 03:44:23.619864",
"name": "QA",
"no_due_date": 0,
"offset_days": 7,
"offset_direction": "Before",
"skip_holidays": 1,
"skip_weekends": 1,
"task_type_calculate_from": null,
"title": null,
"trigger": null,
"triggering_doctype": "Service Address 2",
"weight": 0.0,
"work_type": "Admin"
},
{
"base_date": "Project Start",
"calculate_from": "Service Appointment",
"custom_completion_trigger": null,
"custom_completion_trigger_doctype": null,
"custom_target_percent": 0,
"days": 0,
"description": null,
"docstatus": 0,
"doctype": "Task Type",
"logic_key": null,
"modified": "2025-04-24 14:56:51.838933",
"name": "Admin",
"no_due_date": 0,
"offset_days": 7,
"offset_direction": "Before",
"skip_holidays": 1,
"skip_weekends": 1,
"task_type_calculate_from": null,
"title": null,
"trigger": null,
"triggering_doctype": "Service Address 2",
"weight": 0.0,
"work_type": "Admin"
},
{
"base_date": "Project Start",
"calculate_from": "Service Appointment",
"custom_completion_trigger": null,
"custom_completion_trigger_doctype": null,
"custom_target_percent": 0,
"days": 0,
"description": null,
"docstatus": 0,
"doctype": "Task Type",
"logic_key": null,
"modified": "2024-04-16 11:55:50.883266",
"name": "Scheduling",
"no_due_date": 0,
"offset_days": 7,
"offset_direction": "Before",
"skip_holidays": 1,
"skip_weekends": 1,
"task_type_calculate_from": null,
"title": null,
"trigger": null,
"triggering_doctype": "Service Address 2",
"weight": 0.0,
"work_type": "Admin"
},
{
"base_date": "Project Start",
"calculate_from": "Service Appointment",
"custom_completion_trigger": null,
"custom_completion_trigger_doctype": null,
"custom_target_percent": 0,
"days": 0,
"description": null,
"docstatus": 0,
"doctype": "Task Type",
"logic_key": null,
"modified": "2024-04-19 12:51:25.954969",
"name": "Labor",
"no_due_date": 0,
"offset_days": 7,
"offset_direction": "Before",
"skip_holidays": 1,
"skip_weekends": 1,
"task_type_calculate_from": null,
"title": null,
"trigger": null,
"triggering_doctype": "Service Address 2",
"weight": 0.0,
"work_type": "Admin"
}
]

View file

@ -1,194 +0,0 @@
[
{
"account": null,
"address_line_1": null,
"address_line_2": null,
"city": null,
"company": "Sprinklers Northwest",
"default_in_transit_warehouse": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Warehouse",
"email_id": null,
"is_group": 0,
"is_rejected_warehouse": 0,
"mobile_no": null,
"modified": "2025-01-21 12:05:13.944900",
"name": "Nursery - S",
"old_parent": "All Warehouses - S",
"parent_warehouse": "All Warehouses - S",
"phone_no": null,
"pin": null,
"state": null,
"warehouse_name": "Nursery",
"warehouse_type": null
},
{
"account": null,
"address_line_1": null,
"address_line_2": null,
"city": null,
"company": "Sprinklers Northwest",
"default_in_transit_warehouse": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Warehouse",
"email_id": null,
"is_group": 0,
"is_rejected_warehouse": 0,
"mobile_no": null,
"modified": "2025-01-31 10:23:24.774635",
"name": "Services Stock - S",
"old_parent": "",
"parent_warehouse": null,
"phone_no": null,
"pin": null,
"state": null,
"warehouse_name": "Services Stock",
"warehouse_type": null
},
{
"account": null,
"address_line_1": null,
"address_line_2": null,
"city": null,
"company": "Lowe Fencing",
"default_in_transit_warehouse": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Warehouse",
"email_id": null,
"is_group": 0,
"is_rejected_warehouse": 0,
"mobile_no": null,
"modified": "2024-10-31 14:40:21.144485",
"name": "Fencing Yard - LF",
"old_parent": "",
"parent_warehouse": null,
"phone_no": null,
"pin": null,
"state": null,
"warehouse_name": "Fencing Yard",
"warehouse_type": null
},
{
"account": null,
"address_line_1": null,
"address_line_2": null,
"city": null,
"company": "Sprinklers Northwest",
"default_in_transit_warehouse": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Warehouse",
"email_id": null,
"is_group": 0,
"is_rejected_warehouse": 0,
"mobile_no": null,
"modified": "2025-01-31 10:14:33.005891",
"name": "Completed Ready to Bill - S",
"old_parent": "All Warehouses - S",
"parent_warehouse": "All Warehouses - S",
"phone_no": null,
"pin": null,
"state": null,
"warehouse_name": "Completed Ready to Bill",
"warehouse_type": null
},
{
"account": null,
"address_line_1": null,
"address_line_2": null,
"city": null,
"company": "Sprinklers Northwest",
"default_in_transit_warehouse": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Warehouse",
"email_id": null,
"is_group": 1,
"is_rejected_warehouse": 0,
"mobile_no": null,
"modified": "2024-04-03 13:53:07.446449",
"name": "All Warehouses - S",
"old_parent": "",
"parent_warehouse": "",
"phone_no": null,
"pin": null,
"state": null,
"warehouse_name": "All Warehouses",
"warehouse_type": null
},
{
"account": null,
"address_line_1": null,
"address_line_2": null,
"city": null,
"company": "Sprinklers Northwest",
"default_in_transit_warehouse": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Warehouse",
"email_id": null,
"is_group": 0,
"is_rejected_warehouse": 0,
"mobile_no": null,
"modified": "2025-01-31 09:54:31.268684",
"name": "Field Work - S",
"old_parent": "All Warehouses - S",
"parent_warehouse": "All Warehouses - S",
"phone_no": null,
"pin": null,
"state": null,
"warehouse_name": "Field Work",
"warehouse_type": null
},
{
"account": "Stock In Hand - S",
"address_line_1": null,
"address_line_2": null,
"city": null,
"company": "Sprinklers Northwest",
"default_in_transit_warehouse": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Warehouse",
"email_id": null,
"is_group": 0,
"is_rejected_warehouse": 0,
"mobile_no": null,
"modified": "2024-10-31 16:10:30.017682",
"name": "Parts Shed - S",
"old_parent": "All Warehouses - S",
"parent_warehouse": "All Warehouses - S",
"phone_no": null,
"pin": null,
"state": null,
"warehouse_name": "Parts Shed ",
"warehouse_type": null
},
{
"account": null,
"address_line_1": null,
"address_line_2": null,
"city": null,
"company": "Sprinklers Northwest",
"default_in_transit_warehouse": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Warehouse",
"email_id": null,
"is_group": 1,
"is_rejected_warehouse": 0,
"mobile_no": null,
"modified": "2025-01-21 12:06:12.188216",
"name": "Stores - S",
"old_parent": "",
"parent_warehouse": "",
"phone_no": null,
"pin": null,
"state": null,
"warehouse_name": "Vendor",
"warehouse_type": null
}
]

View file

@ -216,11 +216,6 @@ doc_events = {
} }
fixtures = [ fixtures = [
{"dt": "Company"},
# {"dt": "Account"},
{"dt": "Cost Center"},
{"dt": "Warehouse"},
{"dt": "Fiscal Year"},
{ {
"dt": "Email Template", "dt": "Email Template",
"filters": [ "filters": [
@ -233,16 +228,12 @@ fixtures = [
["custom", "=", 1] ["custom", "=", 1]
] ]
}, },
{ "dt": "Task Type" },
{ {
"dt": "Task", "dt": "Task",
"filters": [ "filters": [
["is_template", "=", 1] ["status", "in", ["Template"]]
] ]
}, },
{ "dt": "Project Template" },
{ "dt": "Bid Meeting Note Form" },
{ "dt": "Holiday List" },
# These don't have reliable flags → export all # These don't have reliable flags → export all
{"dt": "Custom Field"}, {"dt": "Custom Field"},

View file

@ -6,12 +6,10 @@ import frappe
from .utils import create_module from .utils import create_module
import holidays import holidays
from datetime import date, timedelta from datetime import date, timedelta
from erpnext.accounts.doctype.account.chart_of_accounts.chart_of_accounts import create_charts
def after_install(): def after_install():
create_module() create_module()
# add_custom_fields() add_custom_fields()
frappe.db.commit() frappe.db.commit()
# Proper way to refresh metadata # Proper way to refresh metadata
@ -19,21 +17,20 @@ def after_install():
frappe.reload_doctype("Address") frappe.reload_doctype("Address")
frappe.clear_cache(doctype="On-Site Meeting") frappe.clear_cache(doctype="On-Site Meeting")
frappe.reload_doctype("On-Site Meeting") frappe.reload_doctype("On-Site Meeting")
# update_onsite_meeting_fields() update_onsite_meeting_fields()
# update_address_fields() update_address_fields()
# create_companies() check_and_create_holiday_list()
# check_and_create_holiday_list() create_project_templates()
create_task_types()
# create_tasks() # create_tasks()
# create_task_types() create_bid_meeting_note_form_templates()
# create_project_templates() create_accounts()
# create_bid_meeting_note_form_templates()
# create_accounts()
# init_stripe_accounts() # init_stripe_accounts()
build_frontend() build_frontend()
def after_migrate(): def after_migrate():
add_custom_fields() add_custom_fields()
# update_onsite_meeting_fields() update_onsite_meeting_fields()
frappe.db.commit() frappe.db.commit()
# Proper way to refresh metadata for all doctypes with custom fields # Proper way to refresh metadata for all doctypes with custom fields
@ -42,13 +39,13 @@ def after_migrate():
frappe.clear_cache(doctype=doctype) frappe.clear_cache(doctype=doctype)
frappe.reload_doctype(doctype) frappe.reload_doctype(doctype)
# check_and_create_holiday_list() check_and_create_holiday_list()
# create_project_templates() # create_project_templates()
# create_task_types() create_task_types()
# create_tasks() # create_tasks()
# create_bid_meeting_note_form_templates() create_bid_meeting_note_form_templates()
create_accounts() create_accounts()
# create_companies() create_companies()
# init_stripe_accounts() # init_stripe_accounts()
# update_address_fields() # update_address_fields()
@ -1594,24 +1591,126 @@ def create_bid_meeting_note_form_templates():
doc.insert(ignore_permissions=True) doc.insert(ignore_permissions=True)
def create_accounts(): def create_companies():
"""Create necessary companies if they do not exist.""" """Create necessary companies if they do not exist."""
print("\n🔧 Checking for necessary companies...") print("\n🔧 Checking for necessary companies...")
companies = frappe.get_all("Company", pluck="name") companies = [
{
'company_name': 'Veritas Stone',
'abbr': 'VS',
'default_currency': 'USD',
'country': 'United States',
'is_group': 0,
'parent_company': None,
'create_chart_of_accounts_based_on': 'Standard Template',
'chart_of_accounts': 'Standard',
'default_cash_account': 'Cash - VS',
'default_receivable_account': 'Debtors - VS',
'default_payable_account': 'Creditors - VS',
'default_income_account': 'Sales - VS',
'default_expense_account': 'Cost of Goods Sold - VS',
'cost_center': 'Main - VS',
'enable_perpetual_inventory': 1
},
{
'company_name': 'Daniels Landscape Supplies',
'abbr': 'DL',
'default_currency': 'USD',
'country': 'United States',
'is_group': 0,
'parent_company': None,
'create_chart_of_accounts_based_on': 'Standard Template',
'chart_of_accounts': 'Standard',
'default_cash_account': 'Cash - DL',
'default_receivable_account': 'Debtors - DL',
'default_payable_account': 'Creditors - DL',
'default_income_account': 'Sales - DL',
'default_expense_account': 'Cost of Goods Sold - DL',
'cost_center': 'Main - DL',
'enable_perpetual_inventory': 1
},
{
'company_name': 'sprinklersnorthwest (Demo)',
'abbr': 'SD',
'default_currency': 'USD',
'country': 'United States',
'is_group': 0,
'parent_company': None,
'create_chart_of_accounts_based_on': 'Standard Template',
'chart_of_accounts': 'Standard',
'default_cash_account': 'Cash - SD',
'default_receivable_account': 'Debtors - SD',
'default_payable_account': 'Creditors - SD',
'default_income_account': 'Sales - SD',
'default_expense_account': 'Cost of Goods Sold - SD',
'cost_center': 'Main - SD',
'enable_perpetual_inventory': 1
},
{
'company_name': 'Lowe Fencing',
'abbr': 'LF',
'default_currency': 'USD',
'country': 'United States',
'is_group': 0,
'parent_company': None,
'create_chart_of_accounts_based_on': 'Standard Template',
'chart_of_accounts': 'Standard',
'default_cash_account': 'Cash - LF',
'default_receivable_account': 'Debtors - LF',
'default_payable_account': 'Creditors - LF',
'default_income_account': 'Fencing Sales - LF',
'default_expense_account': 'Cost of Goods Sold - LF',
'cost_center': 'Main - LF',
'enable_perpetual_inventory': 1
},
{
'company_name': 'Nuco Yard Care',
'abbr': 'NYC',
'default_currency': 'USD',
'country': 'United States',
'is_group': 0,
'parent_company': None,
'create_chart_of_accounts_based_on': 'Standard Template',
'chart_of_accounts': 'Standard',
'default_cash_account': 'Cash - NYC',
'default_receivable_account': 'Debtors - NYC',
'default_payable_account': 'Creditors - NYC',
'default_income_account': 'Sales - NYC',
'default_expense_account': 'Cost of Goods Sold - NYC',
'cost_center': 'Main - NYC',
'enable_perpetual_inventory': 1
},
{
'company_name': 'Sprinklers Northwest',
'abbr': 'S',
'default_currency': 'USD',
'country': 'United States',
'is_group': 0,
'parent_company': None,
'create_chart_of_accounts_based_on': 'Standard Template',
'chart_of_accounts': 'Standard',
'default_cash_account': 'Undeposited Funds - S',
'default_receivable_account': 'Debtors - S',
'default_payable_account': 'Creditors - S',
'default_income_account': 'Sales - S',
'default_expense_account': 'Cost of Goods Sold - S',
'cost_center': 'Main - S',
'enable_perpetual_inventory': 1
}
]
for company in companies: for company in companies:
if frappe.db.exists("Account", {"company": company}): if frappe.db.exists("Company", company["company_name"]):
print(f"✅ Accounts already exist for company '{company}'. Skipping account creation.")
continue continue
company_doc = frappe.get_doc("Company", company) data = {
create_charts( "doctype": "Company"
company=company.name, }
chart_template=company_doc.chart_template data.update(company)
) doc = frappe.get_doc(data)
doc.insert(ignore_permissions=True)
def create_accounts():
def create_stripe_accounts():
"""Create necessary accounts if they do not exist.""" """Create necessary accounts if they do not exist."""
print("\n🔧 Checking for necessary accounts...") print("\n🔧 Checking for necessary accounts...")
@ -1645,3 +1744,23 @@ def create_stripe_accounts():
doc.insert(ignore_permissions=True, ignore_if_duplicate=True) doc.insert(ignore_permissions=True, ignore_if_duplicate=True)
frappe.db.commit() frappe.db.commit()
def init_stripe_accounts():
"""Initializes the bare configurations for each Stripe Settings doctypes."""
print("\n🔧 Initializing Stripe Settings for companies...")
companies = ["Sprinklers Northwest"]
for company in companies:
if not frappe.db.exists("Stripe Settings", {"company": company}):
doc = frappe.get_doc({
"doctype": "Stripe Settings",
"company": company,
"api_key": "",
"publishable_key": "",
"webhook_secret": "",
"account": f"Stripe Clearing - {company}"
})
doc.insert(ignore_permissions=True)
frappe.db.commit()

View file

@ -1,6 +1,5 @@
import frappe import frappe
from custom_ui.services import ContactService, AddressService, ClientService, DbService from custom_ui.services import ContactService, AddressService, ClientService, DbService
import json
class ServiceAppointmentService: class ServiceAppointmentService:
@ -28,12 +27,9 @@ class ServiceAppointmentService:
return service_appointment return service_appointment
@staticmethod @staticmethod
def update_scheduled_dates(service_appointment_name: str, crew_lead_name: str = None, start_date=None, end_date=None, start_time=None, end_time=None, skip_days=[]): def update_scheduled_dates(service_appointment_name: str, crew_lead_name: str,start_date, end_date, start_time=None, end_time=None):
"""Update the scheduled start and end dates of a Service Appointment.""" """Update the scheduled start and end dates of a Service Appointment."""
print(f"DEBUG: Updating scheduled dates for Service Appointment {service_appointment_name} to start: {start_date}, end: {end_date}") print(f"DEBUG: Updating scheduled dates for Service Appointment {service_appointment_name} to start: {start_date}, end: {end_date}")
if isinstance(skip_days, str):
skip_days = json.loads(skip_days)
print(f"DEBUG: Parsed skip_days: {skip_days}")
service_appointment = DbService.get_or_throw("Service Address 2", service_appointment_name) service_appointment = DbService.get_or_throw("Service Address 2", service_appointment_name)
service_appointment.expected_start_date = start_date service_appointment.expected_start_date = start_date
service_appointment.expected_end_date = end_date service_appointment.expected_end_date = end_date
@ -42,21 +38,6 @@ class ServiceAppointmentService:
service_appointment.expected_start_time = start_time service_appointment.expected_start_time = start_time
if end_time: if end_time:
service_appointment.expected_end_time = end_time service_appointment.expected_end_time = end_time
if skip_days:
current_skip_days
# Compare skip_days with the current skip_days and remove/add as needed
current_skip_days = set([skip_day.date for skip_day in service_appointment.skip_days])
new_skip_days = set(skip_days)
# Remove skip days that are no longer needed
for skip_day in current_skip_days - new_skip_days:
skip_day_doc = service_appointment.skip_days.find(lambda d: d.date == skip_day)
if skip_day_doc:
service_appointment.skip_days.remove(skip_day_doc.name)
print(f"DEBUG: Removed skip day {skip_day} from Service Appointment {service_appointment_name}")
# Add new skip days
for skip_day in new_skip_days - current_skip_days:
service_appointment.append("skip_days", {"date": skip_day})
print(f"DEBUG: Added new skip day {skip_day} for Service Appointment {service_appointment_name}")
service_appointment.save() service_appointment.save()
print(f"DEBUG: Updated scheduled dates for Service Appointment {service_appointment_name}") print(f"DEBUG: Updated scheduled dates for Service Appointment {service_appointment_name}")
return service_appointment return service_appointment

View file

@ -476,13 +476,12 @@ class Api {
return await this.request(FRAPPE_GET_SERVICE_APPOINTMENTS_METHOD, { companies, filters }); return await this.request(FRAPPE_GET_SERVICE_APPOINTMENTS_METHOD, { companies, filters });
} }
static async updateServiceAppointmentScheduledDates(serviceAppointmentName, startDate = null, endDate = null, crewLeadName = null, skippedDays = [],startTime = null, endTime = null) { static async updateServiceAppointmentScheduledDates(serviceAppointmentName, startDate, endDate, crewLeadName, startTime = null, endTime = null) {
return await this.request(FRAPPE_UPDATE_SERVICE_APPOINTMENT_SCHEDULED_DATES_METHOD, { return await this.request(FRAPPE_UPDATE_SERVICE_APPOINTMENT_SCHEDULED_DATES_METHOD, {
serviceAppointmentName, serviceAppointmentName,
startDate, startDate,
endDate, endDate,
crewLeadName, crewLeadName,
skippedDays,
startTime, startTime,
endTime endTime
}) })

View file

@ -1,5 +1,5 @@
<template> <template>
<div class="calendar-container" :class="{ 'skip-mode': skipMode }"> <div class="calendar-container">
<div class="calendar-header"> <div class="calendar-header">
<h2>Weekly Schedule - {{ companyStore.currentCompany }}</h2> <h2>Weekly Schedule - {{ companyStore.currentCompany }}</h2>
<div class="header-controls"> <div class="header-controls">
@ -26,16 +26,6 @@
<v-btn @click="goToThisWeek" variant="outlined" size="small" class="ml-4"> <v-btn @click="goToThisWeek" variant="outlined" size="small" class="ml-4">
This Week This Week
</v-btn> </v-btn>
<v-btn
@click="toggleSkipMode"
:color="skipMode ? 'error' : 'default'"
variant="outlined"
size="small"
class="ml-4"
>
<v-icon left size="small">mdi-content-cut</v-icon>
Skip Day
</v-btn>
<v-menu <v-menu
v-model="showTemplateMenu" v-model="showTemplateMenu"
:close-on-content-click="false" :close-on-content-click="false"
@ -168,36 +158,6 @@
</v-card> </v-card>
</v-dialog> </v-dialog>
<!-- Skip Day Confirmation Dialog -->
<v-dialog v-model="showSkipConfirmation" max-width="400px">
<v-card>
<v-card-title>Skip Day Confirmation</v-card-title>
<v-card-text>
<p>Are you sure you want to skip <strong>{{ skipConfirmationData ? formatDate(skipConfirmationData.date) : '' }}</strong> for job <strong>{{ skipConfirmationData ? skipConfirmationData.job.projectTemplate : '' }}</strong>?</p>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn @click="cancelSkipDay">Cancel</v-btn>
<v-btn color="error" @click="confirmSkipDay">Skip Day</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<!-- Remove Skip Confirmation Dialog -->
<v-dialog v-model="showRemoveSkipConfirmation" max-width="400px">
<v-card>
<v-card-title>Remove Skip Confirmation</v-card-title>
<v-card-text>
<p>Are you sure you want to remove the skip for <strong>{{ removeSkipConfirmationData ? formatDate(removeSkipConfirmationData.date) : '' }}</strong> on job <strong>{{ removeSkipConfirmationData ? removeSkipConfirmationData.job.projectTemplate : '' }}</strong>?</p>
</v-card-text>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn @click="cancelRemoveSkip">Cancel</v-btn>
<v-btn color="error" @click="confirmRemoveSkip">Remove Skip</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
<div class="calendar-main"> <div class="calendar-main">
<!-- Weekly Calendar Grid --> <!-- Weekly Calendar Grid -->
<div class="calendar-section"> <div class="calendar-section">
@ -235,12 +195,10 @@
'holiday': isHoliday(day.date), 'holiday': isHoliday(day.date),
'sunday': isSunday(day.date), 'sunday': isSunday(day.date),
'drag-over': isDragOver && dragOverCell?.foremanId === foreman.name && dragOverCell?.date === day.date, 'drag-over': isDragOver && dragOverCell?.foremanId === foreman.name && dragOverCell?.date === day.date,
'has-skipped-jobs': getSkippedJobsForCell(foreman.name, day.date).length > 0,
}" }"
@dragover="handleDragOver($event, foreman.name, day.date)" @dragover="handleDragOver($event, foreman.name, day.date)"
@dragleave="handleDragLeave" @dragleave="handleDragLeave"
@drop="handleDrop($event, foreman.name, day.date)" @drop="handleDrop($event, foreman.name, day.date)"
@click="skipMode ? handleSkipDayClick(foreman.name, day.date) : null"
> >
<!-- Jobs in this day --> <!-- Jobs in this day -->
<div <div
@ -249,7 +207,7 @@
class="calendar-job" class="calendar-job"
:style="getJobStyle(job, day.date)" :style="getJobStyle(job, day.date)"
:draggable="job.status === 'Scheduled'" :draggable="job.status === 'Scheduled'"
@click.stop="skipMode ? handleSkipDayClick(foreman.name, day.date, job) : showEventDetails({ event: job })" @click.stop="showEventDetails({ event: job })"
@dragstart="job.status === 'Scheduled' ? handleDragStart(job, $event) : null" @dragstart="job.status === 'Scheduled' ? handleDragStart(job, $event) : null"
@dragend="handleDragEnd" @dragend="handleDragEnd"
@mousedown="(job.status === 'Scheduled' || job.status === 'Started') ? startResize($event, job, day.date) : null" @mousedown="(job.status === 'Scheduled' || job.status === 'Started') ? startResize($event, job, day.date) : null"
@ -265,23 +223,6 @@
<div class="resize-handle"></div> <div class="resize-handle"></div>
</div> </div>
<!-- Skipped days -->
<div
v-for="job in getSkippedJobsForCell(foreman.name, day.date)"
:key="`skip-${job.name}`"
class="skipped-day"
:class="getPriorityClass(job.priority)"
>
<span>Skipped</span>
<button
class="remove-skip-btn"
@click.stop="handleRemoveSkip(job, day.date)"
title="Remove skipped day"
>
<v-icon size="small">mdi-close</v-icon>
</button>
</div>
<!-- Holiday connector line for split jobs --> <!-- Holiday connector line for split jobs -->
<template v-if="isHoliday(day.date)"> <template v-if="isHoliday(day.date)">
<div <div
@ -395,22 +336,8 @@ import JobDetailsModal from "../../modals/JobDetailsModal.vue";
const notifications = useNotificationStore(); const notifications = useNotificationStore();
const companyStore = useCompanyStore(); const companyStore = useCompanyStore();
const route = useRoute(); const route = useRoute();
const random = 3
const serviceAptToFind = route.query.apt || null;
// Helper function to get all holidays in a date range const serviceAptToFind = route.query.apt || null;
function getHolidaysInRange(startDate, endDate) {
const start = parseLocalDate(startDate);
const end = parseLocalDate(endDate);
const holidaysInRange = [];
for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) {
const dateStr = toLocalDateString(d);
if (isHoliday(dateStr)) {
holidaysInRange.push(dateStr);
}
}
return holidaysInRange;
}
// Reactive data // Reactive data
const scheduledServices = ref([]); const scheduledServices = ref([]);
@ -436,9 +363,6 @@ const resizeStartDate = ref(null);
const originalEndDate = ref(null); const originalEndDate = ref(null);
const justFinishedResize = ref(false); const justFinishedResize = ref(false);
// Skip mode
const skipMode = ref(false);
// Foremen data (Crews) // Foremen data (Crews)
const foremen = ref([]); const foremen = ref([]);
@ -450,14 +374,6 @@ const showForemenMenu = ref(false);
const showDatePicker = ref(false); const showDatePicker = ref(false);
const selectedDate = ref(null); const selectedDate = ref(null);
// Skip day confirmation
const showSkipConfirmation = ref(false);
const skipConfirmationData = ref(null);
// Remove skip confirmation
const showRemoveSkipConfirmation = ref(false);
const removeSkipConfirmationData = ref(null);
// Project template filter // Project template filter
const selectedProjectTemplates = ref([]); const selectedProjectTemplates = ref([]);
const showTemplateMenu = ref(false); const showTemplateMenu = ref(false);
@ -597,6 +513,20 @@ function getCrewName(foremanId) {
return foreman.customCrew ? `${foreman.employeeName} (Crew ${foreman.customCrew})` : foreman.employeeName; return foreman.customCrew ? `${foreman.employeeName} (Crew ${foreman.customCrew})` : foreman.employeeName;
} }
// Helper function to get all holidays in a date range
function getHolidaysInRange(startDate, endDate) {
const start = parseLocalDate(startDate);
const end = parseLocalDate(endDate);
const holidaysInRange = [];
for (let d = new Date(start); d <= end; d.setDate(d.getDate() + 1)) {
const dateStr = toLocalDateString(d);
if (isHoliday(dateStr)) {
holidaysInRange.push(dateStr);
}
}
return holidaysInRange;
}
// Helper function to calculate job segments (parts between holidays/Sundays) // Helper function to calculate job segments (parts between holidays/Sundays)
function getJobSegments(job) { function getJobSegments(job) {
const startDate = job.expectedStartDate; const startDate = job.expectedStartDate;
@ -617,9 +547,8 @@ function getJobSegments(job) {
for (let d = new Date(start); d <= effectiveEnd; d.setDate(d.getDate() + 1)) { for (let d = new Date(start); d <= effectiveEnd; d.setDate(d.getDate() + 1)) {
const dateStr = toLocalDateString(d); const dateStr = toLocalDateString(d);
// If we hit a holiday, Sunday, or skipped day, close the current segment // If we hit a holiday or Sunday, close the current segment
const isSkipped = job.skipDays && job.skipDays.some(skip => skip.date === dateStr); if (isHoliday(dateStr) || isSunday(dateStr)) {
if (isHoliday(dateStr) || isSunday(dateStr) || isSkipped) {
// Close previous segment if it exists // Close previous segment if it exists
if (segmentStart !== null) { if (segmentStart !== null) {
const prevDate = toLocalDateString(new Date(d.getTime() - 86400000)); // Previous day const prevDate = toLocalDateString(new Date(d.getTime() - 86400000)); // Previous day
@ -729,24 +658,8 @@ const getJobsForCell = (foremanId, date) => {
// Check if this date falls within the job's date range // Check if this date falls within the job's date range
// AND that it's a valid segment start date // AND that it's a valid segment start date
// AND not in skipDays
const segments = getJobSegments(job); const segments = getJobSegments(job);
const isSkipped = job.skipDays && job.skipDays.some(skip => skip.date === date); return segments.some(seg => seg.start === date);
return segments.some(seg => seg.start === date) && !isSkipped;
});
};
// Get skipped jobs for a specific foreman and date
const getSkippedJobsForCell = (foremanId, date) => {
return scheduledServices.value.filter((job) => {
if (job.foreman !== foremanId) return false;
const jobStart = job.expectedStartDate;
const jobEnd = job.expectedEndDate || job.expectedStartDate;
// Check if this date is in the job's skipDays
const isSkipped = job.skipDays && job.skipDays.some(skip => skip.date === date);
return isSkipped && parseLocalDate(date) >= parseLocalDate(jobStart) && parseLocalDate(date) <= parseLocalDate(jobEnd);
}); });
}; };
@ -845,10 +758,6 @@ const goToThisWeek = () => {
weekStartDate.value = getWeekStart(new Date()); weekStartDate.value = getWeekStart(new Date());
}; };
const toggleSkipMode = () => {
skipMode.value = !skipMode.value;
};
// Foremen selection methods // Foremen selection methods
const toggleAllForemen = () => { const toggleAllForemen = () => {
if (selectedForemen.value.length === foremen.value.length) { if (selectedForemen.value.length === foremen.value.length) {
@ -1115,143 +1024,6 @@ const handleDrop = async (event, foremanId, date) => {
draggedService.value = null; draggedService.value = null;
}; };
const handleSkipDayClick = async (foremanId, date, specificJob = null) => {
let job;
if (specificJob) {
job = specificJob;
} else {
// Find jobs that cover this date for this foreman
const jobs = scheduledServices.value.filter(job => {
if (job.foreman !== foremanId) return false;
const start = job.expectedStartDate;
const end = job.expectedEndDate || start;
return date >= start && date <= end;
});
if (jobs.length === 0) {
notifications.addInfo("No jobs found for this day.");
return;
}
// For now, take the first job. In future, could show selection if multiple.
job = jobs[0];
}
// Check if already skipped
const isAlreadySkipped = job.skipDays && job.skipDays.some(skip => skip.date === date);
if (isAlreadySkipped) {
notifications.addInfo("This day is already skipped.");
return;
}
// Show confirmation dialog
skipConfirmationData.value = { job, date };
showSkipConfirmation.value = true;
};
const confirmSkipDay = async () => {
const { job, date } = skipConfirmationData.value;
// Add to skipDays
const newSkipDays = [...(job.skipDays || []), { date }];
// Update local
const serviceIndex = scheduledServices.value.findIndex(s => s.name === job.name);
if (serviceIndex !== -1) {
scheduledServices.value[serviceIndex] = {
...scheduledServices.value[serviceIndex],
skipDays: newSkipDays
};
}
// Call API
try {
await Api.updateServiceAppointmentScheduledDates(
job.name,
job.expectedStartDate,
job.expectedEndDate,
job.foreman,
newSkipDays
);
notifications.addSuccess("Day skipped successfully!");
// Untoggle skip mode
skipMode.value = false;
} catch (error) {
console.error("Error skipping day:", error);
notifications.addError("Failed to skip day");
// Revert
if (serviceIndex !== -1) {
scheduledServices.value[serviceIndex] = {
...scheduledServices.value[serviceIndex],
skipDays: job.skipDays
};
}
}
// Close dialog
showSkipConfirmation.value = false;
skipConfirmationData.value = null;
};
const cancelSkipDay = () => {
showSkipConfirmation.value = false;
skipConfirmationData.value = null;
};
// Handle removing a skipped day
const handleRemoveSkip = async (job, date) => {
// Show confirmation dialog
removeSkipConfirmationData.value = { job, date };
showRemoveSkipConfirmation.value = true;
};
const confirmRemoveSkip = async () => {
const { job, date } = removeSkipConfirmationData.value;
// Remove from skipDays
const newSkipDays = (job.skipDays || []).filter(skip => skip.date !== date);
// Update local
const serviceIndex = scheduledServices.value.findIndex(s => s.name === job.name);
if (serviceIndex !== -1) {
scheduledServices.value[serviceIndex] = {
...scheduledServices.value[serviceIndex],
skipDays: newSkipDays
};
}
// Call API
try {
await Api.updateServiceAppointmentScheduledDates(
job.name,
job.expectedStartDate,
job.expectedEndDate,
job.foreman,
newSkipDays
);
notifications.addSuccess("Skip removed successfully!");
} catch (error) {
console.error("Error removing skip:", error);
notifications.addError("Failed to remove skip");
// Revert
if (serviceIndex !== -1) {
scheduledServices.value[serviceIndex] = {
...scheduledServices.value[serviceIndex],
skipDays: job.skipDays
};
}
}
// Close dialog
showRemoveSkipConfirmation.value = false;
removeSkipConfirmationData.value = null;
};
const cancelRemoveSkip = () => {
showRemoveSkipConfirmation.value = false;
removeSkipConfirmationData.value = null;
};
// Handle dropping scheduled items back to unscheduled // Handle dropping scheduled items back to unscheduled
const handleUnscheduledDragOver = (event) => { const handleUnscheduledDragOver = (event) => {
// Only allow dropping if the dragged job is scheduled // Only allow dropping if the dragged job is scheduled
@ -2125,190 +1897,4 @@ onMounted(async () => {
align-items: center; align-items: center;
line-height: 1.4; line-height: 1.4;
} }
.scheduled-item[draggable="true"]:active {
cursor: grabbing;
}
.priority-urgent {
border-left-color: #f44336 !important;
}
.priority-high {
border-left-color: #ff9800 !important;
}
.priority-medium {
border-left-color: #ffeb3b !important;
}
.priority-low {
border-left-color: #4caf50 !important;
}
.service-title-compact {
font-weight: 600;
font-size: 0.9em;
color: #1976d2;
line-height: 1.2;
}
.service-customer {
font-size: 0.8em;
color: #666;
margin-top: 2px;
}
.service-compact-details {
display: flex;
align-items: center;
gap: 8px;
}
.service-notes-compact {
background-color: #f8f9fa;
padding: 4px 6px;
border-radius: 3px;
border-left: 2px solid #2196f3;
}
.service-notes-compact .text-caption {
font-style: italic;
color: #666;
line-height: 1.3;
}
.no-unscheduled {
text-align: center;
padding: 40px 20px;
color: #666;
}
.day-cell.holiday {
background: repeating-linear-gradient(
45deg,
rgba(255, 193, 7, 0.15),
rgba(255, 193, 7, 0.15) 10px,
rgba(255, 193, 7, 0.05) 10px,
rgba(255, 193, 7, 0.05) 20px
);
border-left: 3px solid #ffc107;
border-right: 3px solid #ffc107;
}
.day-cell.sunday {
background-color: rgba(200, 200, 200, 0.1); /* light gray for Sunday */
}
.holiday-connector {
position: absolute;
left: 4px;
right: 4px;
top: 50%;
height: 3px;
transform: translateY(-50%);
border-top: 3px dotted currentColor;
opacity: 0.6;
pointer-events: none;
z-index: 5;
}
.holiday-connector.priority-urgent {
color: #f44336;
}
.holiday-connector.priority-high {
color: #ff9800;
}
.holiday-connector.priority-medium {
color: #2196f3;
}
.holiday-connector.priority-low {
color: #4caf50;
}
.extend-popup {
position: fixed;
top: 100px;
left: 50%;
transform: translateX(-50%);
background: rgba(33, 150, 243, 0.95);
color: white;
padding: 12px 20px;
border-radius: 8px;
font-size: 1em;
font-weight: 600;
pointer-events: none;
z-index: 10000;
white-space: nowrap;
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.3);
border: 2px solid rgba(255, 255, 255, 0.3);
animation: slideDown 0.2s ease-out;
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateX(-50%) translateY(-10px);
}
to {
opacity: 1;
transform: translateX(-50%) translateY(0);
}
}
.service-address {
font-size: 0.85em;
color: #555;
display: flex;
align-items: center;
line-height: 1.4;
}
.calendar-container.skip-mode {
cursor: crosshair;
}
.calendar-container.skip-mode .day-cell {
cursor: crosshair;
}
.skipped-day {
position: relative;
border-top: 2px dotted #ff0000;
border-bottom: 2px dotted #ff0000;
background: rgba(255, 0, 0, 0.05);
min-height: 40px;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
color: #ff0000;
font-weight: 500;
}
.remove-skip-btn {
position: absolute;
top: 2px;
right: 2px;
background: rgba(255, 255, 255, 0.9);
border-radius: 50%;
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
font-size: 12px;
color: #ff0000;
border: 1px solid #ff0000;
opacity: 0;
transition: opacity 0.2s;
}
.skipped-day:hover .remove-skip-btn {
opacity: 1;
}
</style> </style>