Compare commits

..

146 Commits

Author SHA1 Message Date
Ameya Shenoy
881bb4646b Merge branch 'staging-fixes' into staging 2018-10-23 08:05:33 +00:00
Ameya Shenoy
4293d17602 bumped to version 11.0.3-beta.14 2018-10-23 08:05:33 +00:00
Ameya Shenoy
ca66c7ba14 Merge branch 'master' into staging-fixes 2018-10-23 08:01:13 +00:00
Ameya Shenoy
83fd31973f Merge branch 'hotfix' 2018-10-23 07:58:12 +00:00
Ameya Shenoy
ac64b39562 bumped to version 10.1.63 2018-10-23 07:58:11 +00:00
Ameya Shenoy
c73c576536 Merge pull request #15759 from codingCoffee/salesperson
fix(): fetch correct warehouse for item in report
2018-10-23 13:25:42 +05:30
Shreya Shah
669c5d0298 Merge pull request #15724 from shreyashah115/fix-leave
Do not consider current leave application while submitting leave
2018-10-23 12:31:02 +05:30
Faris Ansari
d3e3c1ba72 Merge pull request #15768 from rohitwaghchaure/market_place_settings_error
[Fix] Marketplace settings permission error
2018-10-23 12:07:21 +05:30
Rohit Waghchaure
55416e08f1 [Fix] Marketplace setting permission error 2018-10-23 11:52:06 +05:30
Shreya
1b105e2575 Add test case 2018-10-23 11:45:57 +05:30
Shreya
60d8a0da1e fix(leave-status): Do not consider current leave application while submitting 2018-10-23 11:45:57 +05:30
Shreya Shah
9db75ecde2 Merge pull request #15766 from Zlash65/fix-mod
[Minor] Travis fix
2018-10-23 11:44:33 +05:30
Zlash65
635d4dbebe subscriber deprecated test case fixes 2018-10-23 11:00:19 +05:30
rohitwaghchaure
cf076f4692 Merge pull request #15753 from Zlash65/fix-mod
[Minor] Field name fix to fetch Supplier
2018-10-23 09:45:39 +05:30
rohitwaghchaure
034429b34d Merge pull request #15756 from rohitwaghchaure/fixed_allow_edit_rate
[Fix] User able to edit the rate in offline POS even if it has no permissions
2018-10-23 09:43:57 +05:30
Ameya Shenoy
a0e533ede5 Merge branch 'master' into staging-fixes 2018-10-22 10:37:14 +00:00
Ameya Shenoy
874866e9f9 Merge branch 'hotfix' 2018-10-22 10:34:35 +00:00
Ameya Shenoy
c365ce8f21 bumped to version 10.1.62 2018-10-22 10:34:35 +00:00
Ameya Shenoy
3a11f34355 fix(): fetch correct warehouse for item in report
Fix 'Sales Person-wise Transaction Summary' Report by fetching the
correct Warehouse for the Item fron the respective, Sales Order/Sales
Invoice/ Delivery Note
2018-10-22 10:15:07 +00:00
Nabin Hait
91eac5a7cf fix(report): Optimization for financial statements 2018-10-22 15:05:40 +05:30
Rohit Waghchaure
aef7a6ec44 [Fix] User able to edit the rate in offline POS even if it has no permissions 2018-10-22 13:51:32 +05:30
Ranjith Kurungadam
ac6e3a69f9 fix: Serial No- allow editing SO, track changes (#15741) 2018-10-22 12:06:54 +05:30
Zlash65
473437931c field name fix 2018-10-22 11:22:12 +05:30
Ameya Shenoy
4215b85e46 Merge branch 'staging-fixes' into staging 2018-10-19 12:56:48 +00:00
Ameya Shenoy
7e97230c92 bumped to version 11.0.3-beta.13 2018-10-19 12:56:48 +00:00
Ameya Shenoy
bbfdc13ab7 Merge branch 'master' into staging-fixes 2018-10-19 12:48:18 +00:00
Ameya Shenoy
6192d24235 Merge branch 'hotfix' 2018-10-19 12:48:17 +00:00
Ameya Shenoy
24fe7286fc bumped to version 10.1.61 2018-10-19 12:48:16 +00:00
Nabin Hait
5d1171678e fix(perpetual inventory): Get warehouse account map only if perpetual inventory enabled (#15743)
* fix(perpetual inventory): Get warehouse account map only if perpetual inventory enabled

* fix(perpetual inventory): Get warehouse account map only if perpetual inventory enabled
2018-10-19 18:03:13 +05:30
Saif
b4cf72c770 Adding "Include UOM" in Reports with Qty and Rates (#15541)
* Added Include UOM field for Stock Balane, Stock Ledger and Stock Projected Qty

* Add columns in result list-of-lists instead of converting reports to list-of-dicts

* For requested changes
-Merged conversion factor query with item detail queries
-Ensuring snail_case
-Made columns consistently list-of-dicts
2018-10-18 17:59:47 +05:30
Saif
3c9155e406 [Minor Fix] Force toggle display Net Total field when default taxes are fetched (#15532)
* Minor fix for the problem that Net Total, Net Rate, Net Amount field would not be shown when default taxes were fetched

* Prevent net_rate from becoming NaN

* -Fixed problem that party_account_currency was not set in mapped document
-Fixed problem that discount amount was not recalculated (in mapped document)
-Fixed problem that set_dynamic_fields would work only on certain condition that led to showing Total (Company Currency) field even when using company currency
2018-10-18 17:57:56 +05:30
deepeshgarg007
25edac451d Production Analytics Query Report (#15673)
* Production Analytics Query Report

* Changes in production analytics report

* Updated json file and other changes
2018-10-18 17:43:41 +05:30
Raffael Meyer
25e9db5e81 Do not display gender for companies (#15728) 2018-10-18 16:49:49 +05:30
Nabin Hait
500ddc94c7 fix(gle): GL Entry for invoices before introduction of rounding_adjustment (#15732) 2018-10-18 16:48:28 +05:30
Charles-Henri Decultot
7a7615ed66 Safe encode payer name (#15726) 2018-10-18 12:28:06 +05:30
Aditya Hase
007fbfbfb7 [Feature] ERPNext Quickbooks Migrator (#15718)
* Create QuickBooks Connector Single DocType

* Create interface for user authorization and obtaining authorization code

* Obtain Access token using authorization code

* Fetch a random customer

* Schedule fetching as a background job

* Save fetched customer

* Fetch all customers, take care of pagination

* Save fetched customers

* Create a custom field for storing Quickbooks ID

* Don't save already saved customers

* Commit every successful insert

* No need of allow_guest=True

* Fetch Items as well

* Store Customer Addresses as well.

* Remove redundant custom field creation code

* Stupid refactoring

* Some more refactoring

* Fetch and Save Suppliers as well

* Save accounts. Really a hack as of now.

* Fetch and save invoices, Take care of child items as well

* Fetch Taxes as well

* Set currency on Sales Invoice

* Correctly Link Items, Handle markups

* Don't enqueue, Need to wait forever for testing sometimes

* Set margin rate correctly

* Correct fieldname is tax_amount not amount

* Fetch with maximum possible batch size

* Don't print unnecessary info

* Fetch Journal Entries

* Fetch Purchase Invoices (Bill)

* Don't perform reauthentication if you already have an access_token

* Don't need those print statements anymore

* Refresh access_token if request fails

* Fetch Payment Entry(Payment)

* Map QB items to ERPNext rather than other way around

* Don't need a huge comment block as of now

* Fetch Payment Entries against Purchase Invoices (BillPayment)

* Rename Quickbooks Connector to Migrator

* Make oauth settings configurable

* Make company configurable

* Make default accounts configurable

* Fetch accounts and other masters separately

* Show realtime progress

* Check if entries exist before attempting insert

* Suppress other annoying messages

* Tracebacks are good for health

* Don't want rounded total

* Don't call fetch after authorization (Need to somehow separate these)

* Make credit_to account payable

* When generating payment entry mention bank_account as well

* Cleanup

* Add custom buttons and reflect current state in form ui

* Show necessary fields on form depending on the current state

* Cleanup

* Minor fixes

* Set income and expense account on items.

* Set currency for Account.

* Stupid VSCode

* Remove redundant code

* Check for existing Payment and BillPayment correctly

* Cache API response for faster development

* Don't maintain stock for now, Seems to solve the issue with 'Stock Received but not billed'

* Cleanup

* Add methods to remove inserted data completely (Development)

* Don't commit in every iteration

* Set account head based on TaxRate in Sales Invoice

* Fetch and cache TaxCode

* Add methods to fetch TaxCode and TaxRate from cache

* Set item wise tax breakup, Don't use Actual Tax

* Use both TaxRateLists

* Set Itemwise tax on Purchase Invoice as well

* Set bank_amount, while creating payment entries

* Remove print statements

* Add Shipping in taxes child table of Sales Invoice

* Set posting date on Payment Entries against Invoices

* Fetch and save expenses as Journal Entries

* Fetch and save Deposits as Journal Entries

* Fetch and Save Credit and Debit Notes

* Fetch and save SalesReceipt

* Record Shipping as Item instead of Tax

* Minor Fixes

* Fetch Advance Payments

* Set account_type during Account creation

* Choose receivable account in Invoice based on currency

* Remove receivable_account field

* Account type is already set during account creation

* Set receivable account based on currency in Sales Receipt and Credit Memo

* Set receivable account on Customer

* Save Company Preferences

* Set shipping_account based on company preferences

* Set cost center in Sales Invoice Items and Taxes

* Make Account name unique in case of duplicate account name

* Fetch and Save TaxPayment as Journal Entry

* Record UndepositedFunds Account in cache if found

* Credit UndepositedFunds account when mentioned in Deposit

* Debit Cashback account as well if mentioned in Deposit

* Set currency conversion rate

* Set is_group field correctly for accounts

* Preserve account hierarchy

* Use quickbooks_id and company together for filtering

* Make new custom field 'company' on Supplier Customer and Item

* Use comapny field for filtering Customer, Item, Supplier

* Shipping Account is only available if shipping is enabled for comapny

* Invoice might not have TxnTaxDetail.TaxLine

* Lookup TaxRate account correctly

* TaxCode might not have SalesTaxRateList PurchaseTaxRateList or Both

* TaxCode might not have SalesTaxRateList and PurchaseTaxRateList

* Remove unnecessary UI elements

* Allow multiple companies to have customers with same name

* Refactor account_type

* Create a leaf an account for every group account

* Item and Tax list creation needs more information

* Supports discount in Invoice

* Save Invoice as Journal Entry when itemwise details are unavailable

* Credit=True represents a refund rather than charge

* Mode of Payment not synced, setting as Cash for now

* Tax code may also be set for an entire invoice

* Fetch General Ledger Report correctly

* Refactor fetching entries from General Ledger Report

* Tax Payment is the same as Sales Tax Payment and Purchase Tax Payment

* append_number_if_name_exists is stupid, Reimplementing

* Don't guess credit/debit for Tax Payment and Advanced Payment

* Bill Payment shouldn't assume full payment

* Save Payment as Journal Entry

* Make Client ID and Client Secret Default

* Remove unused python imports

* removed are_accounts_synced()

* Don't store translated values in database

* Endpoints as a field

* Major refactor - functions to methods

* Major Refactor Functions to Methods

* Major Refactor Fix Stuff

* Minor Changes

* Save Refund As well

* Minor Refactor (SI varations to SI, PI variations to PI)

* Record Inventory Qty Adjust Entries

* QBM Final Touches

* Make changes suggested in review
2018-10-17 17:50:00 +05:30
rohitwaghchaure
e2afbb7abe Merge pull request #15703 from SaiFi0102/AR-AP-PDC-Fix
[For staging-fixes] Fixed PDC data in AR/AP report
2018-10-17 15:57:28 +05:30
Ameya Shenoy
961b7dee9d Merge branch 'staging-fixes' into staging 2018-10-17 09:44:11 +00:00
Ameya Shenoy
a7a32d7400 bumped to version 11.0.3-beta.12 2018-10-17 09:44:11 +00:00
Ameya Shenoy
77b60928bf Merge branch 'master' into staging-fixes 2018-10-17 09:39:31 +00:00
Ameya Shenoy
bbd8b04012 Merge branch 'hotfix' 2018-10-17 09:04:11 +00:00
Ameya Shenoy
bb1b6b42e2 bumped to version 10.1.60 2018-10-17 09:04:11 +00:00
Ameya Shenoy
4fdbff7456 Merge pull request #15547 from Zlash65/demo-refactor
Demo data refactor
2018-10-16 17:34:09 +05:30
deepeshgarg007
0cbb9b54fa Deprecating subscriber doctype (#15695)
* Depricating subscriber doctype

* Removed naming series
2018-10-16 14:39:16 +05:30
Shreya Shah
8e71074e1c fix(report): Add column for Item Name (#15702) 2018-10-16 14:36:49 +05:30
Shreya Shah
e45868a3c6 fix(discount-amount): Print hide discount_amount if print without amount (#15705) 2018-10-16 14:34:56 +05:30
Shreya Shah
ff0deedca9 fix(discount-amount): Print hide discount_amount if print without amount (#15704) 2018-10-16 14:34:30 +05:30
Shreya Shah
22731e39ba Merge pull request #15376 from jodeq/show_project-attachments-in-portal
[Proposal] Show project attachments in portal view
2018-10-16 14:29:51 +05:30
Shreya Shah
bfb88f7839 Merge pull request #15701 from shreyashah115/item-stock
Add column for Item Name in Item Price Stock report
2018-10-16 14:22:46 +05:30
Shreya
82660913a5 fix(report): Add column for Item Name 2018-10-16 12:15:56 +05:30
Shreya
8aca56836b fix(margin): Make user avatar display in line 2018-10-16 12:00:46 +05:30
rohitwaghchaure
19be730b9c Merge pull request #15700 from joeirimpan/staging-fixes
feat: Add provision for prebilled subscription invoices
2018-10-16 11:36:29 +05:30
rohitwaghchaure
a5a926967b Update accounts_receivable.py 2018-10-16 11:27:23 +05:30
Joe Paul
666e6e665b feat: Add provision for prebilled subscription invoices
(cherry picked from commit db33e6304d)
2018-10-16 10:17:40 +05:30
deepeshgarg007
4bb90add1d Currency symbol bug fix (#15698) 2018-10-15 19:07:49 +05:30
Nabin Hait
44ec05f79b fix(bom): deadlock issue via bom replace tool (#15694) 2018-10-15 18:56:16 +05:30
Charles-Henri Decultot
615571dd21 Add safe decode for payer name (#15692) 2018-10-15 18:26:02 +05:30
Bibin
7844b79274 [Bug-Fix] accounts_receivable.html (#15688)
* Update accounts_receivable.html

In the print format and PDF the total was showing as 0 (Zero) , when I made these changes it fixed the issue

* Update accounts_receivable.html
2018-10-15 18:25:26 +05:30
deepeshgarg007
7c443264a4 Currency symbol bug fix (#15690) 2018-10-15 18:22:28 +05:30
JodeQ
10dfd4a48f Show project attachments in portal view 2018-10-15 14:28:27 +02:00
Ameya Shenoy
3185b37360 Merge branch 'staging-fixes' into staging 2018-10-15 12:24:12 +00:00
Ameya Shenoy
8d0195246d bumped to version 11.0.3-beta.11 2018-10-15 12:24:12 +00:00
Ameya Shenoy
4fa58359c8 Merge pull request #15689 from codingCoffee/pat
fix(patch): reload patient
2018-10-15 17:49:42 +05:30
Ameya Shenoy
102eb998ac fix(patch): reload healthacre doctypes
Signed-off-by: Ameya Shenoy <shenoy.ameya@gmail.com>
2018-10-15 17:40:02 +05:30
Nabin Hait
3c29967d27 Fixed merge conflict 2018-10-15 15:43:21 +05:30
Nabin Hait
ea75295bb3 Merge branch 'hotfix' 2018-10-15 15:41:25 +05:30
Nabin Hait
d2c643eb0b bumped to version 10.1.59 2018-10-15 16:11:25 +06:00
rohitwaghchaure
94fcb0e9f9 [Enhance] Add user image in the employee from the user (#15680) 2018-10-15 14:57:46 +05:30
Jamsheer
2a966f26af fix: patch - change healthcare desktop icons (#15683) 2018-10-15 14:54:29 +05:30
Ranjith Kurungadam
741bd29b74 fix: Patient Appointment Calendar (#15684) 2018-10-15 14:52:38 +05:30
rohitwaghchaure
0d2a4c6a59 [Fix] TDS Payable Monthly report is not working (#15666) 2018-10-15 11:09:17 +05:30
deepeshgarg007
42510a411f [Bug-Fix]V11 Accounts Receivable print showing zero values (#15667)
* Bug Fix

* Print report bug fixes
2018-10-15 11:08:04 +05:30
rohitwaghchaure
3362d6b948 [Fix] Precision issue in the expense claim (#15678) 2018-10-15 11:07:13 +05:30
Mangesh-Khairnar
8c62ab4af0 [Enhancement] Email birthday reminder (#15559)
* Update hooks.py

* modified date for reload_doc (#15027)

* Single email for multiple birthdays and test
2018-10-11 17:06:10 +05:30
Shreya Shah
314c97cbf1 Fix for supplier quotation (#15659) 2018-10-11 16:59:40 +05:30
Alchez
a16f0f4423 fix(item_defaults): handle multiple item defaults for a company (#15634) 2018-10-11 16:56:46 +05:30
Charles-Henri Decultot
64b6421fce Add event in transaction base correction (#15631) 2018-10-11 16:54:26 +05:30
Charles-Henri Decultot
6c743bebf2 Check for prefix before return EcritureNum (#15629) 2018-10-11 16:51:29 +05:30
Charles-Henri Decultot
50447b195d Compatibility with Py2 (#15653) 2018-10-11 16:48:38 +05:30
Shreya Shah
e9890a3ec8 fix(patch): Check if meta object has naming_series field (#15651) 2018-10-11 16:28:59 +05:30
Faris Ansari
4833b4c274 fix: Default Series in naming series patch (#15656) 2018-10-11 16:27:05 +05:30
Stavros Anastasiadis
a398d6bf4f Allow Same Item Multiple Items (#15657) 2018-10-11 16:25:37 +05:30
Ameya Shenoy
dc279ded15 Merge branch 'staging-fixes' into staging 2018-10-11 06:58:13 +00:00
Ameya Shenoy
d791af8331 bumped to version 11.0.3-beta.10 2018-10-11 06:58:13 +00:00
rohitwaghchaure
b1241caf48 Merge pull request #15650 from rohitwaghchaure/fix_gst_state_issue
[Fix] Nontype object has no attribute gst_state
2018-10-11 10:53:46 +05:30
Rohit Waghchaure
b6a735e021 [Fix] Nontype object has no attribute gst_state 2018-10-11 10:40:34 +05:30
Shreya Shah
785f1aa96d fix(print): Update idx if grouping same items (#15647) 2018-10-11 10:14:25 +05:30
Shreya Shah
2291323c65 fix(shipping-address-display): Fetch shipping address display as per the shipping address (#15643) 2018-10-11 10:13:27 +05:30
deepeshgarg007
1cb1074f6b Bug Fix (#15640) 2018-10-10 16:15:30 +05:30
Sagar Vora
d92f3ac480 Fix 'transporter info' section in Delivery Note (#15565)
- create is_transporter checkbox in supplier doctype
- new field transporter (supplier with is_transporter checked)
- created fields driver and driver_name
- removed GST India fields from core doctype
- removed readonly & allow_on_submit from fields (delivery trip applicable only for in-house delivery)
- read_only transporter_name field (kept for backwards compatibility)
- made necessary changes in delivery_trip implementation
- hidden section's fields from print (preserving v10 convention)
- added transporter field to 'Driver' doctype
- added queries for transporter and driver fields
- GST India fields in regional module
- Fix e-waybill report
2018-10-10 14:51:26 +05:30
Shreya Shah
dd87e0f1e2 fix(leave-type): Drop column max_days_allowed (#15642) 2018-10-10 14:48:49 +05:30
rohitwaghchaure
4cfff7829b Added validation to check duplicate student leave application (#15636) 2018-10-10 14:47:48 +05:30
Shreya Shah
3855156b7d fix(project): If Project has no Tasks, let the status be set as Completed (#15639) 2018-10-10 14:45:40 +05:30
Jamsheer
14c6ab0ee9 [fix] Healthcare field and desktop icon (#15638)
* Test Inpatient Record - Fix

* Test Inpatient Record - Fix

* Healthcare - Patch rename_healthcare_doctype_and_fields - Updated

* Healthcare - Desktop Icons - Updated

* Healthcare - Patch change  in healthcare desktop icons

* Healthcare Util - fix - appointments valid in fee validity

* Healthcare Settings - field label change

* Patient allow rename

* fix: remove unused variable
2018-10-10 14:44:36 +05:30
Zlash65
6a8957b430 item data updated with retail data 2018-10-10 14:28:17 +05:30
Zlash65
62592d3c44 setup data for retail added 2018-10-10 14:28:17 +05:30
Zlash65
fd9c451909 company name picked up dynamically, domainification 2018-10-10 14:28:17 +05:30
Zlash65
d1fbaf8f32 custom field added for item - domainification, password changed 2018-10-10 14:28:17 +05:30
Zlash65
275ef826a4 codacy fixes 2018-10-10 14:28:17 +05:30
Zlash65
8b1133cb24 item data fix for default supplier, exception handling for purchase order 2018-10-10 14:28:17 +05:30
Zlash65
d080a17961 minor random trigger changes and exception handling 2018-10-10 14:28:16 +05:30
Zlash65
e64dcfc2f9 timesheet logic changed to job card 2018-10-10 14:28:16 +05:30
Zlash65
e895845ae1 import fix 2018-10-10 14:28:16 +05:30
Zlash65
523f77e82b make_rm_stock_entry fix 2018-10-10 14:28:16 +05:30
Zlash65
dcf7401104 random time fix and other minor fixes 2018-10-10 14:28:16 +05:30
Zlash65
143d4da901 Production Plan fix 2018-10-10 14:28:16 +05:30
Zlash65
c24d2fdf6c setup leave & expense approver for each department
- assign approver in expense claim
2018-10-10 14:28:16 +05:30
Zlash65
a259466643 add relevant department to employees 2018-10-10 14:28:16 +05:30
Zlash65
0309bbee30 function call requires company as parameter 2018-10-10 14:28:16 +05:30
Zlash65
796bffbee1 fix payroll and stock related data 2018-10-10 14:28:16 +05:30
Zlash65
4c07970545 remove user permission from HR Manager user 2018-10-10 14:28:16 +05:30
Zlash65
fa7c8a9f8b update employee and user records 2018-10-10 14:28:16 +05:30
Saurabh
99c064305f Merge branch 'master' into staging-fixes 2018-10-09 17:55:33 +05:30
Saurabh
75c1682e61 Merge branch 'hotfix' 2018-10-09 17:55:32 +05:30
Saurabh
2dc8972794 bumped to version 10.1.58 2018-10-09 18:25:32 +06:00
Saurabh
f786eccdf9 Merge pull request #15633 from Zlash65/setup-fix
[Minor] Setup Wizard failing fix
2018-10-09 17:49:54 +05:30
Zlash65
a1036ad50b setup wizard failing fix 2018-10-09 17:38:28 +05:30
Shreya Shah
8a4bcefec4 fix(accounts-receivable): Column values in Print and PDF (#15621) 2018-10-08 18:34:01 +05:30
Shreya Shah
5b34d00bc0 fix(accounts-receivable): Column values in Print and PDF (#15622) 2018-10-08 18:20:51 +05:30
Nabin Hait
d2c5b50842 fix(warehouse-account): get warehouse account map fallback handling (#15625)
* fix(warehouse-account): get warehouse account map fallback handling

* fix: import issue
2018-10-08 18:19:53 +05:30
Ameya Shenoy
cf91f34ffa Merge branch 'staging-fixes' into staging 2018-10-08 09:43:48 +00:00
Ameya Shenoy
563b1d153b bumped to version 11.0.3-beta.9 2018-10-08 09:43:48 +00:00
Ameya Shenoy
ecba14e6cf Merge branch 'master' into staging-fixes 2018-10-08 09:39:49 +00:00
Ameya Shenoy
ee3b788024 Merge branch 'hotfix' 2018-10-08 09:37:37 +00:00
Ameya Shenoy
b509b06edf bumped to version 10.1.57 2018-10-08 09:37:37 +00:00
Zarrar
87441bf62e columns without fieldname's data not shown (#15618) 2018-10-08 14:34:34 +05:30
Zarrar
5fcccda883 [Minor] Supplier Quotation (#15578)
* throw meaningful error if RFQ does not have selected supplier

* Update supplier_quotation.py

* codacy fix
2018-10-08 14:30:53 +05:30
Shreya Shah
4fb9230d16 Add missing method link_to_mrs to buying.js (#15613) 2018-10-08 14:18:03 +05:30
Shreya Shah
95d93913ce fix(link_to_mr): Add missing method to buying.js (#15616) 2018-10-08 14:17:37 +05:30
Shreya Shah
37d3686372 fix(setup_taxes): Pop if frappe.message_log (#15615) 2018-10-08 14:17:16 +05:30
Ameya Shenoy
8cafb5fbbb Merge branch 'staging-fixes' into staging 2018-10-08 07:27:35 +00:00
Ameya Shenoy
0bd254b02b bumped to version 11.0.3-beta.8 2018-10-08 07:27:35 +00:00
rohitwaghchaure
5e466bace4 Removed update_job_card_reference method (#15614) 2018-10-08 12:36:45 +05:30
Shreya Shah
c2857fd2cc fix(setup_taxes): Pop if frappe.message_log (#15611) 2018-10-08 12:35:18 +05:30
Jamsheer
063cf9c582 Jam staging fixes (#15608)
* Test Inpatient Record - Fix

* Test Inpatient Record - Fix
2018-10-08 10:48:42 +05:30
Ameya Shenoy
36be62b927 Merge branch 'staging-fixes' into staging 2018-10-07 07:59:34 +00:00
Ameya Shenoy
cfdd629fd7 bumped to version 11.0.3-beta.7 2018-10-07 07:59:34 +00:00
Ameya Shenoy
272956980d Merge pull request #15606 from codingCoffee/abc
fix: make location from warehouse patch
2018-10-07 13:25:05 +05:30
Ameya Shenoy
f7b5b7beb4 fix: make location from warehouse patch
- optimization by preventing patch execution if Asset doesn't exist
2018-10-07 13:08:00 +05:30
Ameya Shenoy
39903647ae Merge branch 'staging-fixes' into staging 2018-10-07 06:23:22 +00:00
Ameya Shenoy
cd9be8f0a6 bumped to version 11.0.3-beta.6 2018-10-07 06:23:22 +00:00
Shreya Shah
5615cb4735 Set default only if customer_address not found (#15605)
* Set default only if customer_address not found

* Similar fix for Purchase Invoice and shipping_address
2018-10-07 11:42:07 +05:30
Shreya Shah
e7e269d4a4 [Error] Display appropriate msg if company is different for TDS (#15601)
* fix(tds): Display appropriate msg if company is different

* Update tax_withholding_category.py
2018-10-06 17:56:21 +05:30
Ameya Shenoy
b8c1897a80 Merge pull request #15603 from Zlash65/rectify
[Minor] Deferred Expense
2018-10-06 16:43:22 +05:30
Zlash65
58a080a1b1 add voucher detail no while creating gl entry 2018-10-06 16:34:58 +05:30
Saif Ur Rehman
423549e084 Fixed PDC data in AR/AP report:
-Get PDC date from posting_date instead of reference date since posting_date is the date at which the post dated cheque can be cleared
-Get PDC data from submitted documents only
2018-09-08 15:48:55 +05:00
129 changed files with 13380 additions and 9873 deletions

View File

@@ -5,7 +5,7 @@ import frappe
from erpnext.hooks import regional_overrides
from frappe.utils import getdate
__version__ = '10.1.56'
__version__ = '10.1.63'
def get_default_company(user=None):
'''Get default company for user'''

View File

@@ -157,6 +157,7 @@ def book_deferred_income_or_expense(doc, start_date=None, end_date=None):
"credit": base_amount,
"credit_in_account_currency": amount,
"cost_center": item.cost_center,
"voucher_detail_no": item.name,
'posting_date': booking_end_date,
'project': project
}, account_currency)

View File

@@ -123,7 +123,7 @@ class PaymentRequest(Document):
"reference_doctype": "Payment Request",
"reference_docname": self.name,
"payer_email": self.email_to or frappe.session.user,
"payer_name": data.customer_name,
"payer_name": frappe.safe_encode(data.customer_name),
"order_id": self.name,
"currency": self.currency
})

View File

@@ -123,6 +123,7 @@ class PurchaseInvoice(BuyingController):
def set_missing_values(self, for_validate=False):
if not self.credit_to:
self.credit_to = get_party_account("Supplier", self.supplier, self.company)
self.party_account_currency = frappe.db.get_value("Account", self.credit_to, "account_currency", cache=True)
if not self.due_date:
self.due_date = get_due_date(self.posting_date, "Supplier", self.supplier, self.company, self.bill_date)
@@ -208,7 +209,8 @@ class PurchaseInvoice(BuyingController):
if self.update_stock:
self.validate_item_code()
self.validate_warehouse()
warehouse_account = get_warehouse_account_map()
if auto_accounting_for_stock:
warehouse_account = get_warehouse_account_map()
for item in self.get("items"):
# in case of auto inventory accounting,
@@ -377,7 +379,10 @@ class PurchaseInvoice(BuyingController):
return gl_entries
def make_supplier_gl_entry(self, gl_entries):
grand_total = self.rounded_total or self.grand_total
# Checked both rounding_adjustment and rounded_total
# because rounded_total had value even before introcution of posting GLE based on rounded total
grand_total = self.rounded_total if (self.rounding_adjustment and self.rounded_total) else self.grand_total
if grand_total:
# Didnot use base_grand_total to book rounding loss gle
grand_total_in_company_currency = flt(grand_total * self.conversion_rate,
@@ -401,7 +406,8 @@ class PurchaseInvoice(BuyingController):
# item gl entries
stock_items = self.get_stock_items()
expenses_included_in_valuation = self.get_company_default("expenses_included_in_valuation")
warehouse_account = get_warehouse_account_map()
if self.update_stock and self.auto_accounting_for_stock:
warehouse_account = get_warehouse_account_map()
voucher_wise_stock_value = {}
if self.update_stock:

View File

@@ -310,6 +310,7 @@ class SalesInvoice(SellingController):
if not self.debit_to:
self.debit_to = get_party_account("Customer", self.customer, self.company)
self.party_account_currency = frappe.db.get_value("Account", self.debit_to, "account_currency", cache=True)
if not self.due_date and self.customer:
self.due_date = get_due_date(self.posting_date, "Customer", self.customer, self.company)
@@ -715,7 +716,9 @@ class SalesInvoice(SellingController):
return gl_entries
def make_customer_gl_entry(self, gl_entries):
grand_total = self.rounded_total or self.grand_total
# Checked both rounding_adjustment and rounded_total
# because rounded_total had value even before introcution of posting GLE based on rounded total
grand_total = self.rounded_total if (self.rounding_adjustment and self.rounded_total) else self.grand_total
if grand_total:
# Didnot use base_grand_total to book rounding loss gle
grand_total_in_company_currency = flt(grand_total * self.conversion_rate,

View File

@@ -1,2 +0,0 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt

View File

@@ -1,129 +0,0 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"autoname": "field:subscriber_name",
"beta": 0,
"creation": "2018-02-24 11:17:46.809140",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "customer",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Customer",
"length": 0,
"no_copy": 0,
"options": "Customer",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fetch_from": "customer.customer_name",
"fieldname": "subscriber_name",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Subscriber Name",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 1
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-07-11 15:13:30.056470",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Subscriber",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1,
"track_seen": 0
}

View File

@@ -1,9 +0,0 @@
# -*- coding: utf-8 -*-
# Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
from frappe.model.document import Document
class Subscriber(Document):
pass

View File

@@ -1,14 +0,0 @@
from frappe import _
def get_data():
return {
'heatmap': True,
'heatmap_message': _('This is based on transactions against this Subscriber. See timeline below for details'),
'fieldname': 'subscriber',
'transactions': [
{
'label': _('Subscriptions'),
'items': ['Subscription']
}
]
}

View File

@@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
@@ -20,7 +21,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "subscriber",
"fieldname": "customer",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
@@ -29,10 +30,10 @@
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Subscriber",
"label": "Customer",
"length": 0,
"no_copy": 0,
"options": "Subscriber",
"options": "Customer",
"permlevel": 0,
"precision": "",
"print_hide": 0,
@@ -437,6 +438,38 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "generate_invoice_at_period_start",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Generate Invoice At Beginning Of Period",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@@ -814,7 +847,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-08-21 16:15:44.533482",
"modified": "2018-10-14 10:38:55.545540",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Subscription",
@@ -890,4 +923,4 @@
"track_changes": 1,
"track_seen": 0,
"track_views": 0
}
}

View File

@@ -239,7 +239,7 @@ class Subscription(Document):
invoice = frappe.new_doc('Sales Invoice')
invoice.set_posting_time = 1
invoice.posting_date = self.current_invoice_start
invoice.customer = self.get_customer(self.subscriber)
invoice.customer = self.customer
# Subscription is better suited for service items. I won't update `update_stock`
# for that reason
@@ -282,13 +282,6 @@ class Subscription(Document):
return invoice
@staticmethod
def get_customer(subscriber_name):
"""
Returns the `Customer` linked to the `Subscriber`
"""
return frappe.db.get_value('Subscriber', subscriber_name, 'customer')
def get_items_from_plans(self, plans, prorate=0):
"""
Returns the `Item`s linked to `Subscription Plan`
@@ -297,7 +290,7 @@ class Subscription(Document):
prorate_factor = get_prorata_factor(self.current_invoice_end, self.current_invoice_start)
items = []
customer = self.get_customer(self.subscriber)
customer = self.customer
for plan in plans:
item_code = frappe.db.get_value("Subscription Plan", plan.plan, "item")
if not prorate:
@@ -321,6 +314,23 @@ class Subscription(Document):
self.save()
@property
def is_postpaid_to_invoice(self):
return getdate(nowdate()) > getdate(self.current_invoice_end) or \
(getdate(nowdate()) >= getdate(self.current_invoice_end) and getdate(self.current_invoice_end) == getdate(self.current_invoice_start)) and \
not self.has_outstanding_invoice()
@property
def is_prepaid_to_invoice(self):
if not self.generate_invoice_at_period_start:
return False
if self.is_new_subscription():
return True
# Check invoice dates and make sure it doesn't have outstanding invoices
return getdate(nowdate()) >= getdate(self.current_invoice_start) and not self.has_outstanding_invoice()
def process_for_active(self):
"""
Called by `process` if the status of the `Subscription` is 'Active'.
@@ -330,7 +340,7 @@ class Subscription(Document):
2. Change the `Subscription` status to 'Past Due Date'
3. Change the `Subscription` status to 'Cancelled'
"""
if getdate(nowdate()) > getdate(self.current_invoice_end) or (getdate(nowdate()) >= getdate(self.current_invoice_end) and getdate(self.current_invoice_end) == getdate(self.current_invoice_start)) and not self.has_outstanding_invoice():
if self.is_postpaid_to_invoice or self.is_prepaid_to_invoice:
self.generate_invoice()
if self.current_invoice_is_past_due():
self.status = 'Past Due Date'
@@ -338,7 +348,7 @@ class Subscription(Document):
if self.current_invoice_is_past_due() and getdate(nowdate()) > getdate(self.current_invoice_end):
self.status = 'Past Due Date'
if self.cancel_at_period_end and getdate(nowdate()) > self.current_invoice_end:
if self.cancel_at_period_end and getdate(nowdate()) > getdate(self.current_invoice_end):
self.cancel_subscription_at_period_end()
def cancel_subscription_at_period_end(self):

View File

@@ -41,24 +41,14 @@ def create_plan():
plan.billing_interval_count = 14
plan.insert()
def create_subscriber():
if not frappe.db.exists('Subscriber', '_Test Customer'):
subscriber = frappe.new_doc('Subscriber')
subscriber.subscriber_name = '_Test Customer'
subscriber.customer = '_Test Customer'
subscriber.insert()
class TestSubscription(unittest.TestCase):
def setUp(self):
create_plan()
create_subscriber()
def test_create_subscription_with_trial_with_correct_period(self):
subscription = frappe.new_doc('Subscription')
subscription.subscriber = '_Test Customer'
subscription.customer = '_Test Customer'
subscription.trial_period_start = nowdate()
subscription.trial_period_end = add_days(nowdate(), 30)
subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
@@ -75,7 +65,7 @@ class TestSubscription(unittest.TestCase):
def test_create_subscription_without_trial_with_correct_period(self):
subscription = frappe.new_doc('Subscription')
subscription.subscriber = '_Test Customer'
subscription.customer = '_Test Customer'
subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
subscription.save()
@@ -91,7 +81,7 @@ class TestSubscription(unittest.TestCase):
def test_create_subscription_trial_with_wrong_dates(self):
subscription = frappe.new_doc('Subscription')
subscription.subscriber = '_Test Customer'
subscription.customer = '_Test Customer'
subscription.trial_period_end = nowdate()
subscription.trial_period_start = add_days(nowdate(), 30)
subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
@@ -101,7 +91,7 @@ class TestSubscription(unittest.TestCase):
def test_create_subscription_multi_with_different_billing_fails(self):
subscription = frappe.new_doc('Subscription')
subscription.subscriber = '_Test Customer'
subscription.customer = '_Test Customer'
subscription.trial_period_end = nowdate()
subscription.trial_period_start = add_days(nowdate(), 30)
subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
@@ -112,7 +102,7 @@ class TestSubscription(unittest.TestCase):
def test_invoice_is_generated_at_end_of_billing_period(self):
subscription = frappe.new_doc('Subscription')
subscription.subscriber = '_Test Customer'
subscription.customer = '_Test Customer'
subscription.start = '2018-01-01'
subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
subscription.insert()
@@ -129,7 +119,7 @@ class TestSubscription(unittest.TestCase):
def test_status_goes_back_to_active_after_invoice_is_paid(self):
subscription = frappe.new_doc('Subscription')
subscription.subscriber = '_Test Customer'
subscription.customer = '_Test Customer'
subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
subscription.start = '2018-01-01'
subscription.insert()
@@ -159,7 +149,7 @@ class TestSubscription(unittest.TestCase):
settings.save()
subscription = frappe.new_doc('Subscription')
subscription.subscriber = '_Test Customer'
subscription.customer = '_Test Customer'
subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
subscription.start = '2018-01-01'
subscription.insert()
@@ -182,7 +172,7 @@ class TestSubscription(unittest.TestCase):
settings.save()
subscription = frappe.new_doc('Subscription')
subscription.subscriber = '_Test Customer'
subscription.customer = '_Test Customer'
subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
subscription.start = '2018-01-01'
subscription.insert()
@@ -200,7 +190,7 @@ class TestSubscription(unittest.TestCase):
def test_subscription_invoice_days_until_due(self):
subscription = frappe.new_doc('Subscription')
subscription.subscriber = '_Test Customer'
subscription.customer = '_Test Customer'
subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
subscription.days_until_due = 10
subscription.start = add_months(nowdate(), -1)
@@ -218,7 +208,7 @@ class TestSubscription(unittest.TestCase):
settings.save()
subscription = frappe.new_doc('Subscription')
subscription.subscriber = '_Test Customer'
subscription.customer = '_Test Customer'
subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
subscription.start = '2018-01-01'
subscription.insert()
@@ -242,7 +232,7 @@ class TestSubscription(unittest.TestCase):
def test_subscription_remains_active_during_invoice_period(self):
subscription = frappe.new_doc('Subscription')
subscription.subscriber = '_Test Customer'
subscription.customer = '_Test Customer'
subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
subscription.save()
subscription.process() # no changes expected
@@ -268,7 +258,7 @@ class TestSubscription(unittest.TestCase):
def test_subscription_cancelation(self):
subscription = frappe.new_doc('Subscription')
subscription.subscriber = '_Test Customer'
subscription.customer = '_Test Customer'
subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
subscription.save()
subscription.cancel_subscription()
@@ -284,7 +274,7 @@ class TestSubscription(unittest.TestCase):
settings.save()
subscription = frappe.new_doc('Subscription')
subscription.subscriber = '_Test Customer'
subscription.customer = '_Test Customer'
subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
subscription.save()
@@ -319,7 +309,7 @@ class TestSubscription(unittest.TestCase):
settings.save()
subscription = frappe.new_doc('Subscription')
subscription.subscriber = '_Test Customer'
subscription.customer = '_Test Customer'
subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
subscription.save()
subscription.cancel_subscription()
@@ -339,7 +329,7 @@ class TestSubscription(unittest.TestCase):
settings.save()
subscription = frappe.new_doc('Subscription')
subscription.subscriber = '_Test Customer'
subscription.customer = '_Test Customer'
subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
subscription.save()
subscription.cancel_subscription()
@@ -363,7 +353,7 @@ class TestSubscription(unittest.TestCase):
settings.save()
subscription = frappe.new_doc('Subscription')
subscription.subscriber = '_Test Customer'
subscription.customer = '_Test Customer'
subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
subscription.start = '2018-01-01'
subscription.insert()
@@ -397,7 +387,7 @@ class TestSubscription(unittest.TestCase):
settings.save()
subscription = frappe.new_doc('Subscription')
subscription.subscriber = '_Test Customer'
subscription.customer = '_Test Customer'
subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
subscription.start = '2018-01-01'
subscription.insert()
@@ -434,7 +424,7 @@ class TestSubscription(unittest.TestCase):
settings.save()
subscription = frappe.new_doc('Subscription')
subscription.subscriber = '_Test Customer'
subscription.customer = '_Test Customer'
subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
subscription.start = '2018-01-01'
subscription.insert()
@@ -463,7 +453,7 @@ class TestSubscription(unittest.TestCase):
def test_restart_active_subscription(self):
subscription = frappe.new_doc('Subscription')
subscription.subscriber = '_Test Customer'
subscription.customer = '_Test Customer'
subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
subscription.save()
@@ -473,7 +463,7 @@ class TestSubscription(unittest.TestCase):
def test_subscription_invoice_discount_percentage(self):
subscription = frappe.new_doc('Subscription')
subscription.subscriber = '_Test Customer'
subscription.customer = '_Test Customer'
subscription.additional_discount_percentage = 10
subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
subscription.save()
@@ -488,7 +478,7 @@ class TestSubscription(unittest.TestCase):
def test_subscription_invoice_discount_amount(self):
subscription = frappe.new_doc('Subscription')
subscription.subscriber = '_Test Customer'
subscription.customer = '_Test Customer'
subscription.additional_discount_amount = 11
subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
subscription.save()
@@ -500,3 +490,51 @@ class TestSubscription(unittest.TestCase):
self.assertEqual(invoice.apply_discount_on, 'Grand Total')
subscription.delete()
def test_prepaid_subscriptions(self):
# Create a non pre-billed subscription, processing should not create
# invoices.
subscription = frappe.new_doc('Subscription')
subscription.customer = '_Test Customer'
subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
subscription.save()
subscription.process()
self.assertEqual(len(subscription.invoices), 0)
# Change the subscription type to prebilled and process it.
# Prepaid invoice should be generated
subscription.generate_invoice_at_period_start = True
subscription.save()
subscription.process()
self.assertEqual(len(subscription.invoices), 1)
def test_prepaid_subscriptions_with_prorate_true(self):
settings = frappe.get_single('Subscription Settings')
to_prorate = settings.prorate
settings.prorate = 1
settings.save()
subscription = frappe.new_doc('Subscription')
subscription.customer = '_Test Customer'
subscription.generate_invoice_at_period_start = True
subscription.append('plans', {'plan': '_Test Plan Name', 'qty': 1})
subscription.save()
subscription.cancel_subscription()
self.assertEqual(len(subscription.invoices), 1)
current_inv = subscription.get_current_invoice()
self.assertEqual(current_inv.status, "Unpaid")
diff = flt(date_diff(nowdate(), subscription.current_invoice_start) + 1)
plan_days = flt(date_diff(subscription.current_invoice_end, subscription.current_invoice_start) + 1)
prorate_factor = flt(diff / plan_days)
self.assertEqual(flt(current_inv.grand_total, 2), flt(prorate_factor * 900, 2))
settings.prorate = to_prorate
settings.save()
subscription.delete()

View File

@@ -19,6 +19,9 @@ def get_party_tax_withholding_details(ref_doc):
fy = get_fiscal_year(ref_doc.posting_date, company=ref_doc.company)
tax_details = get_tax_withholding_details(tax_withholding_category, fy[0], ref_doc.company)
if not tax_details:
frappe.throw(_('Please set associated account in Tax Withholding Category {0} against Company {1}')
.format(tax_withholding_category, ref_doc.company))
tds_amount = get_tds_amount(ref_doc, tax_details, fy)
tax_row = get_tax_row(tax_details, tds_amount)
return tax_row

View File

@@ -22,17 +22,18 @@ class DuplicatePartyAccountError(frappe.ValidationError): pass
@frappe.whitelist()
def get_party_details(party=None, account=None, party_type="Customer", company=None, posting_date=None,
bill_date=None, price_list=None, currency=None, doctype=None, ignore_permissions=False, fetch_payment_terms_template=True):
bill_date=None, price_list=None, currency=None, doctype=None, ignore_permissions=False, fetch_payment_terms_template=True, party_address=None, shipping_address=None):
if not party:
return {}
if not frappe.db.exists(party_type, party):
frappe.throw(_("{0}: {1} does not exists").format(party_type, party))
return _get_party_details(party, account, party_type,
company, posting_date, bill_date, price_list, currency, doctype, ignore_permissions, fetch_payment_terms_template)
company, posting_date, bill_date, price_list, currency, doctype, ignore_permissions, fetch_payment_terms_template, party_address, shipping_address)
def _get_party_details(party=None, account=None, party_type="Customer", company=None, posting_date=None,
bill_date=None, price_list=None, currency=None, doctype=None, ignore_permissions=False, fetch_payment_terms_template=True):
bill_date=None, price_list=None, currency=None, doctype=None, ignore_permissions=False,
fetch_payment_terms_template=True, party_address=None, shipping_address=None):
out = frappe._dict(set_account_and_due_date(party, account, party_type, company, posting_date, bill_date, doctype))
party = out[party_type.lower()]
@@ -45,7 +46,7 @@ def _get_party_details(party=None, account=None, party_type="Customer", company=
out["taxes_and_charges"] = set_taxes(party.name, party_type, posting_date, company, out.customer_group, out.supplier_group)
out["payment_terms_template"] = get_pyt_term_template(party.name, party_type, company)
set_address_details(out, party, party_type, doctype, company)
set_address_details(out, party, party_type, doctype, company, party_address, shipping_address)
set_contact_details(out, party, party_type)
set_other_values(out, party, party_type)
set_price_list(out, party, party_type, price_list)
@@ -71,19 +72,17 @@ def _get_party_details(party=None, account=None, party_type="Customer", company=
return out
def set_address_details(out, party, party_type, doctype=None, company=None):
def set_address_details(out, party, party_type, doctype=None, company=None, party_address=None, shipping_address=None):
billing_address_field = "customer_address" if party_type == "Lead" \
else party_type.lower() + "_address"
out[billing_address_field] = get_default_address(party_type, party.name)
out[billing_address_field] = party_address or get_default_address(party_type, party.name)
if doctype:
out.update(get_fetch_values(doctype, billing_address_field, out[billing_address_field]))
# address display
out.address_display = get_address_display(out[billing_address_field])
# shipping address
if party_type in ["Customer", "Lead"]:
out.shipping_address_name = get_party_shipping_address(party_type, party.name)
out.shipping_address_name = shipping_address or get_party_shipping_address(party_type, party.name)
out.shipping_address = get_address_display(out["shipping_address_name"])
if doctype:
out.update(get_fetch_values(doctype, 'shipping_address_name', out.shipping_address_name))
@@ -97,7 +96,8 @@ def set_address_details(out, party, party_type, doctype=None, company=None):
elif doctype and doctype == "Purchase Invoice":
out.update(get_company_address(company))
if out.company_address:
out["shipping_address"] = out["company_address"]
out["shipping_address"] = shipping_address or out["company_address"]
out.shipping_address_display = get_address_display(out["shipping_address"])
out.update(get_fetch_values(doctype, 'shipping_address', out.shipping_address))
get_regional_address_details(out, doctype, company)

View File

@@ -161,21 +161,21 @@
</td>
{% } %}
<td style="text-align: right">
{%= format_currency(data[i]["Invoiced Amount"], data[i]["currency"]) %}</td>
{%= format_currency(data[i]["invoiced_amount"], data[i]["currency"]) %}</td>
{% if(!filters.show_pdc_in_print) { %}
<td style="text-align: right">
{%= format_currency(data[i]["Paid Amount"], data[i]["currency"]) %}</td>
{%= format_currency(data[i]["paid_amount"], data[i]["currency"]) %}</td>
<td style="text-align: right">
{%= report.report_name === "Accounts Receivable" ? format_currency(data[i]["Credit Note"], data[i]["currency"]) : format_currency(data[i]["Debit Note"], data[i]["currency"]) %}</td>
{%= report.report_name === "Accounts Receivable" ? format_currency(data[i]["credit_note"], data[i]["currency"]) : format_currency(data[i]["debit_note"], data[i]["currency"]) %}</td>
{% } %}
<td style="text-align: right">
{%= format_currency(data[i]["Outstanding Amount"], data[i]["currency"]) %}</td>
{%= format_currency(data[i]["outstanding_amount"], data[i]["currency"]) %}</td>
{% if(filters.show_pdc_in_print) { %}
{% if(report.report_name === "Accounts Receivable") { %}
<td style="text-align: right">
{%= data[i][__("Customer LPO")] %}</td>
{%= data[i]["po_no"] %}</td>
{% } %}
<td style="text-align: right">{%= frappe.datetime.str_to_user(data[i][__("PDC/LC Date")]) %}</td>
<td style="text-align: right">{%= data[i][__("PDC/LC Ref")] %}</td>
@@ -189,15 +189,15 @@
{% } %}
<td><b>{%= __("Total") %}</b></td>
<td style="text-align: right">
{%= format_currency(data[i]["Invoiced Amount"], data[i]["currency"] ) %}</td>
{%= format_currency(data[i]["invoiced_amount"], data[i]["currency"] ) %}</td>
{% if(!filters.show_pdc_in_print) { %}
<td style="text-align: right">
{%= format_currency(data[i]["Paid Amount"], data[i]["currency"]) %}</td>
<td style="text-align: right">{%= report.report_name === "Accounts Receivable" ? format_currency(data[i]["Credit Note"], data[i]["currency"]) : format_currency(data[i]["Debit Note"], data[i]["currency"]) %} </td>
{%= format_currency(data[i]["paid_amount"], data[i]["currency"]) %}</td>
<td style="text-align: right">{%= report.report_name === "Accounts Receivable" ? format_currency(data[i]["credit_note"], data[i]["currency"]) : format_currency(data[i]["Debit Note"], data[i]["currency"]) %} </td>
{% } %}
<td style="text-align: right">
{%= format_currency(data[i]["Outstanding Amount"], data[i]["currency"]) %}</td>
{%= format_currency(data[i]["outstanding_amount"], data[i]["currency"]) %}</td>
{% if(filters.show_pdc_in_print) { %}
{% if(report.report_name === "Accounts Receivable") { %}
@@ -238,4 +238,4 @@
{% } %}
</tbody>
</table>
<p class="text-right text-muted">{{ __("Printed On ") }}{%= frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string()) %}</p>
<p class="text-right text-muted">{{ __("Printed On ") }}{%= frappe.datetime.str_to_user(frappe.datetime.get_datetime_as_string()) %}</p>

View File

@@ -83,6 +83,7 @@ class ReceivablePayableReport(object):
"{range3}-{above}".format(range3=cint(self.filters["range3"])+ 1, above=_("Above"))):
columns.append({
"label": label,
"fieldname":label,
"fieldtype": "Currency",
"options": "currency",
"width": 120
@@ -104,9 +105,13 @@ class ReceivablePayableReport(object):
]
if args.get('party_type') == 'Customer':
columns += [_("Customer LPO") + ":Data:100"]
columns.append({
"label": _("Customer LPO"),
"fieldtype": "Data",
"fieldname": "po_no",
"width": 100,
})
columns += [_("Delivery Note") + ":Data:100"]
if args.get("party_type") == "Customer":
columns += [
_("Territory") + ":Link/Territory:80",
@@ -448,14 +453,14 @@ def get_pdc_details(party_type, report_date):
for pdc in frappe.db.sql("""
select
pref.reference_name as invoice_no, pent.party, pent.party_type,
max(pent.reference_date) as pdc_date, sum(ifnull(pref.allocated_amount,0)) as pdc_amount,
max(pent.posting_date) as pdc_date, sum(ifnull(pref.allocated_amount,0)) as pdc_amount,
GROUP_CONCAT(pent.reference_no SEPARATOR ', ') as pdc_ref
from
`tabPayment Entry` as pent inner join `tabPayment Entry Reference` as pref
on
(pref.parent = pent.name)
where
pent.docstatus < 2 and pent.reference_date >= %s
pent.docstatus < 2 and pent.posting_date > %s
and pent.party_type = %s
group by pent.party, pref.reference_name""", (report_date, party_type), as_dict=1):
pdc_details.setdefault((pdc.invoice_no, pdc.party), pdc)
@@ -469,18 +474,23 @@ def get_pdc_details(party_type, report_date):
for pdc in frappe.db.sql("""
select
jea.reference_name as invoice_no, jea.party, jea.party_type,
max(je.cheque_date) as pdc_date, sum(ifnull({0},0)) as pdc_amount,
max(je.posting_date) as pdc_date, sum(ifnull({0},0)) as pdc_amount,
GROUP_CONCAT(je.cheque_no SEPARATOR ', ') as pdc_ref
from
`tabJournal Entry` as je inner join `tabJournal Entry Account` as jea
on
(jea.parent = je.name)
where
je.docstatus < 2 and je.cheque_date >= %s
je.docstatus < 2 and je.posting_date > %s
and jea.party_type = %s
group by jea.party, jea.reference_name""".format(amount_field), (report_date, party_type), as_dict=1):
if (pdc.invoice_no, pdc.party) in pdc_details:
pdc_details[(pdc.invoice_no, pdc.party)]["pdc_amount"] += pdc.pdc_amount
key = (pdc.invoice_no, pdc.party)
pdc_details[key]["pdc_amount"] += pdc.pdc_amount
if pdc.pdc_ref:
pdc_details[key]["pdc_ref"] += ", " + pdc.pdc_ref
if pdc.pdc_date:
pdc_details[key]["pdc_date"] = max(pdc_details[key]["pdc_date"], pdc.pdc_date)
else:
pdc_details.setdefault((pdc.invoice_no, pdc.party), pdc)

View File

@@ -339,19 +339,20 @@ def set_gl_entries_by_account(
additional_conditions = get_additional_conditions(from_date, ignore_closing_entries, filters)
accounts = frappe.db.sql_list("""select name from `tabAccount`
where lft >= %s and rgt <= %s""", (root_lft, root_rgt))
additional_conditions += " and account in ('{}')"\
.format("', '".join([frappe.db.escape(d) for d in accounts]))
gl_entries = frappe.db.sql("""select posting_date, account, debit, credit, is_opening, fiscal_year, debit_in_account_currency, credit_in_account_currency, account_currency from `tabGL Entry`
where company=%(company)s
{additional_conditions}
and posting_date <= %(to_date)s
and account in (select name from `tabAccount`
where lft >= %(lft)s and rgt <= %(rgt)s)
order by account, posting_date""".format(additional_conditions=additional_conditions),
{
"company": company,
"from_date": from_date,
"to_date": to_date,
"lft": root_lft,
"rgt": root_rgt,
"cost_center": filters.cost_center,
"project": filters.project
},

View File

@@ -8,6 +8,7 @@ frappe.query_reports["TDS Payable Monthly"] = {
"fieldname":"company",
"label": __("Company"),
"fieldtype": "Link",
"options": "Company",
"default": frappe.defaults.get_default('company')
},
{

View File

@@ -64,13 +64,16 @@ def get_result(filters):
total_amount_credited += k.credit
rate = [i.tax_withholding_rate for i in tds_doc.rates
if i.fiscal_year == gle_map[d][0].fiscal_year][0]
if i.fiscal_year == gle_map[d][0].fiscal_year]
if getdate(filters.from_date) <= gle_map[d][0].posting_date \
and getdate(filters.to_date) >= gle_map[d][0].posting_date:
out.append([supplier.pan, supplier.name, tds_doc.name,
supplier.supplier_type, rate, total_amount_credited, tds_deducted,
gle_map[d][0].posting_date, "Purchase Invoice", d])
if rate and len(rate) > 0:
rate = rate[0]
if getdate(filters.from_date) <= gle_map[d][0].posting_date \
and getdate(filters.to_date) >= gle_map[d][0].posting_date:
out.append([supplier.pan, supplier.name, tds_doc.name,
supplier.supplier_type, rate, total_amount_credited, tds_deducted,
gle_map[d][0].posting_date, "Purchase Invoice", d])
return out

View File

@@ -128,7 +128,7 @@ frappe.ui.form.on("Request for Quotation",{
doctype: "Supplier",
order_by: "name",
fields: ["name"],
filters: [["Supplier", "supplier_group_name", "=", args.supplier_group]]
filters: [["Supplier", "supplier_group", "=", args.supplier_group]]
},
callback: load_suppliers

File diff suppressed because it is too large Load Diff

View File

@@ -60,7 +60,12 @@ class SupplierQuotation(BuyingController):
for rfq in rfq_list:
doc = frappe.get_doc('Request for Quotation', rfq)
doc_sup = frappe.get_all('Request for Quotation Supplier', filters=
{'parent': doc.name, 'supplier': self.supplier}, fields=['name', 'quote_status'])[0]
{'parent': doc.name, 'supplier': self.supplier}, fields=['name', 'quote_status'])
doc_sup = doc_sup[0] if doc_sup else None
if not doc_sup:
frappe.throw(_("Supplier {0} not found in {1}").format(self.supplier,
"<a href='desk#Form/Request for Quotation/{0}'> Request for Quotation {0} </a>".format(doc.name)))
quote_status = _('Received')
for item in doc.items:
@@ -152,4 +157,4 @@ def make_quotation(source_name, target_doc=None):
}
}, target_doc)
return doclist
return doclist

View File

@@ -293,6 +293,16 @@ def get_data():
"label": _("Patient"),
"hidden": 1
},
{
"module_name": "Healthcare Practitioner",
"color": "#2ecc71",
"icon": "fa fa-user-md",
"doctype": "Healthcare Practitioner",
"type": "link",
"link": "List/Healthcare Practitioner",
"label": _("Healthcare Practitioner"),
"hidden": 1
},
{
"module_name": "Patient Appointment",
"color": "#934F92",
@@ -322,6 +332,36 @@ def get_data():
"link": "List/Lab Test",
"label": _("Lab Test"),
"hidden": 1
},
{
"module_name": "Vital Signs",
"color": "#2ecc71",
"icon": "fa fa-thermometer-empty",
"doctype": "Vital Signs",
"type": "list",
"link": "List/Vital Signs",
"label": _("Vital Signs"),
"hidden": 1
},
{
"module_name": "Clinical Procedure",
"color": "#FF888B",
"icon": "fa fa-medkit",
"doctype": "Clinical Procedure",
"type": "list",
"link": "List/Clinical Procedure",
"label": _("Clinical Procedure"),
"hidden": 1
},
{
"module_name": "Inpatient Record",
"color": "#7578f6",
"icon": "fa fa-list-alt",
"doctype": "Inpatient Record",
"type": "list",
"link": "List/Inpatient Record",
"label": _("Inpatient Record"),
"hidden": 1
},
{
"module_name": "Hub",

View File

@@ -708,22 +708,24 @@ class AccountsController(TransactionBase):
def group_similar_items(self):
group_item_qty = {}
group_item_amount = {}
# to update serial number in print
count = 0
for item in self.items:
group_item_qty[item.item_code] = group_item_qty.get(item.item_code, 0) + item.qty
group_item_amount[item.item_code] = group_item_amount.get(item.item_code, 0) + item.amount
duplicate_list = []
for item in self.items:
if item.item_code in group_item_qty:
count += 1
item.qty = group_item_qty[item.item_code]
item.amount = group_item_amount[item.item_code]
item.rate = flt(flt(item.amount) / flt(item.qty), item.precision("rate"))
item.idx = count
del group_item_qty[item.item_code]
else:
duplicate_list.append(item)
for item in duplicate_list:
self.remove(item)

View File

@@ -68,7 +68,8 @@ class BuyingController(StockController):
# set contact and address details for supplier, if they are not mentioned
if getattr(self, "supplier", None):
self.update_if_missing(get_party_details(self.supplier, party_type="Supplier", ignore_permissions=self.flags.ignore_permissions, doctype=self.doctype, company=self.company))
self.update_if_missing(get_party_details(self.supplier, party_type="Supplier", ignore_permissions=self.flags.ignore_permissions,
doctype=self.doctype, company=self.company, party_address=self.supplier_address, shipping_address=self.get('shipping_address')))
self.set_missing_item_details(for_validate)

View File

@@ -44,6 +44,7 @@ class SellingController(StockController):
set_default_income_account_for_item(self)
def set_missing_values(self, for_validate=False):
super(SellingController, self).set_missing_values(for_validate)
# set contact and address details for customer, if they are not mentioned
@@ -61,10 +62,10 @@ class SellingController(StockController):
party_details = _get_party_details(self.customer,
ignore_permissions=self.flags.ignore_permissions,
doctype=self.doctype, company=self.company,
fetch_payment_terms_template=fetch_payment_terms_template)
fetch_payment_terms_template=fetch_payment_terms_template,
party_address=self.customer_address, shipping_address=self.shipping_address_name)
if not self.meta.get_field("sales_team"):
party_details.pop("sales_team")
self.update_if_missing(party_details)
elif getattr(self, "lead", None):

View File

@@ -70,6 +70,7 @@ class calculate_taxes_and_totals(object):
if item.rate_with_margin > 0 else item.rate
item.net_rate = item.rate
item.discount_amount = item.price_list_rate - item.rate
item.amount = flt(item.rate * item.qty, item.precision("amount"))
item.net_amount = item.amount

View File

@@ -287,6 +287,7 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
"depends_on": "eval:!doc.organization_lead",
"fieldname": "gender",
"fieldtype": "Link",
"hidden": 0,
@@ -1521,4 +1522,4 @@
"track_changes": 0,
"track_seen": 0,
"track_views": 0
}
}

View File

@@ -1,72 +1,92 @@
[
{
"date_of_birth": "1982-01-03",
"date_of_joining": "2001-10-10",
"employee_name": "Dikman Shervashidze Shervashidze",
"gender": "Female",
"user_id": "DikmanShervashidze@example.com"
},
{
"date_of_birth": "1959-02-03",
"date_of_joining": "1976-09-16",
"employee_name": "Zukutakitoteka",
"gender": "Female",
"user_id": "Zukutakitoteka@example.com"
},
{
"date_of_birth": "1982-03-03",
"date_of_joining": "2000-06-16",
"employee_name": "Hatsue Kashiwagi",
"gender": "Female",
"user_id": "HatsueKashiwagi@example.com"
},
{
"date_of_birth": "1945-04-04",
"date_of_joining": "1969-07-01",
"employee_name": "Nuran Verkleij",
"gender": "Female",
"user_id": "NuranVerkleij@example.com"
},
{
"date_of_birth": "1978-05-03",
"date_of_joining": "1999-12-24",
"employee_name": "\u0414\u043c\u0438\u0442\u0440\u0438\u0439 \u041f\u0438\u0440\u043e\u0433\u043e\u0432",
"gender": "Male",
"user_id": "aromn@example.com"
},
{
"date_of_birth": "1964-06-03",
"date_of_joining": "1981-08-05",
"employee_name": "Tilde Lindqvist",
"gender": "Female",
"user_id": "TildeLindqvist@example.com"
},
{
"date_of_birth": "1982-07-03",
"date_of_joining": "2006-06-10",
"employee_name": "Micha\u0142 Sobczak",
"gender": "Male",
"user_id": "MichalSobczak@example.com"
},
{
"date_of_birth": "1969-08-03",
"date_of_joining": "1993-10-21",
"employee_name": "Gabrielle Loftus",
"gender": "Female",
"user_id": "GabrielleLoftus@example.com"
},
{
"date_of_birth": "1982-09-03",
"date_of_joining": "2005-09-06",
"employee_name": "Vakhita Ryzaev",
"gender": "Male",
"user_id": "VakhitaRyzaev@example.com"
},
{
"date_of_birth": "1985-10-03",
"date_of_joining": "2007-12-25",
"employee_name": "Charmaine Gaudreau",
"gender": "Female",
"user_id": "CharmaineGaudreau@example.com"
}
{
"date_of_birth": "1982-01-03",
"date_of_joining": "2001-10-10",
"employee_name": "Diana Prince",
"first_name": "Diana",
"last_name": "Prince",
"gender": "Female",
"user_id": "DianaPrince@example.com"
},
{
"date_of_birth": "1959-02-03",
"date_of_joining": "1976-09-16",
"employee_name": "Zatanna Zatara",
"gender": "Female",
"user_id": "ZatannaZatara@example.com",
"first_name": "Zatanna",
"last_name": "Zatara"
},
{
"date_of_birth": "1982-03-03",
"date_of_joining": "2000-06-16",
"employee_name": "Holly Granger",
"gender": "Female",
"user_id": "HollyGranger@example.com",
"first_name": "Holly",
"last_name": "Granger"
},
{
"date_of_birth": "1945-04-04",
"date_of_joining": "1969-07-01",
"employee_name": "Neptunia Aquaria",
"gender": "Female",
"user_id": "NeptuniaAquaria@example.com",
"first_name": "Neptunia",
"last_name": "Aquaria"
},
{
"date_of_birth": "1978-05-03",
"date_of_joining": "1999-12-24",
"employee_name": "Arthur Curry",
"gender": "Male",
"user_id": "ArthurCurry@example.com",
"first_name": "Arthur",
"last_name": "Curry"
},
{
"date_of_birth": "1964-06-03",
"date_of_joining": "1981-08-05",
"employee_name": "Thalia Al Ghul",
"gender": "Female",
"user_id": "ThaliaAlGhul@example.com",
"first_name": "Thalia",
"last_name": "Al Ghul"
},
{
"date_of_birth": "1982-07-03",
"date_of_joining": "2006-06-10",
"employee_name": "Maxwell Lord",
"gender": "Male",
"user_id": "MaxwellLord@example.com",
"first_name": "Maxwell",
"last_name": "Lord"
},
{
"date_of_birth": "1969-08-03",
"date_of_joining": "1993-10-21",
"employee_name": "Grace Choi",
"gender": "Female",
"user_id": "GraceChoi@example.com",
"first_name": "Grace",
"last_name": "Choi"
},
{
"date_of_birth": "1982-09-03",
"date_of_joining": "2005-09-06",
"employee_name": "Vandal Savage",
"gender": "Male",
"user_id": "VandalSavage@example.com",
"first_name": "Vandal",
"last_name": "Savage"
},
{
"date_of_birth": "1985-10-03",
"date_of_joining": "2007-12-25",
"employee_name": "Caitlin Snow",
"gender": "Female",
"user_id": "CaitlinSnow@example.com",
"first_name": "Caitlin",
"last_name": "Snow"
}
]

View File

@@ -1,337 +1,493 @@
[
{
"default_supplier": "Asiatic Solutions",
"item_defaults": [{
"default_warehouse": "Stores"
}],
"description": "For Upper Bearing",
"image": "/assets/erpnext_demo/images/disc.png",
"item_code": "Disc Collars",
"item_group": "Raw Material",
"item_name": "Disc Collars"
},
{
"default_supplier": "Nan Duskin",
"item_defaults": [{
"default_warehouse": "Stores"
}],
"description": "CAST IRON, MCMASTER PART NO. 3710T13",
"image": "/assets/erpnext_demo/images/bearing.jpg",
"item_code": "Bearing Block",
"item_group": "Raw Material",
"item_name": "Bearing Block"
},
{
"default_supplier": null,
"item_defaults": [{
"default_warehouse": "Finished Goods"
}],
"description": "Wind Mill C Series for Commercial Use 18ft",
"image": "/assets/erpnext_demo/images/wind-turbine-2.png",
"item_code": "Wind MIll C Series",
"item_group": "Products",
"item_name": "Wind MIll C Series"
},
{
"default_supplier": null,
"item_defaults": [{
"default_warehouse": "Finished Goods"
}],
"description": "Wind Mill A Series for Home Use 9ft",
"image": "/assets/erpnext_demo/images/wind-turbine.png",
"item_code": "Wind Mill A Series",
"item_group": "Products",
"item_name": "Wind Mill A Series"
},
{
"default_supplier": null,
"item_defaults": [{
"default_warehouse": "Finished Goods"
}],
"description": "Small Wind Turbine for Home Use\n\n\n<!-- html -->",
"image": "/assets/erpnext_demo/images/wind-turbine-1.jpg",
"item_code": "Wind Turbine",
"item_group": "Products",
"item_name": "Wind Turbine",
"has_variants": 1,
"has_serial_no": 1,
"attributes":[
{ "attribute": "Size" }
]
},
{
"default_supplier": "HomeBase",
"item_defaults": [{
"default_warehouse": "Stores"
}],
"description": "1.5 in. Diameter x 36 in. Mild Steel Tubing",
"image": null,
"item_code": "Bearing Pipe",
"item_group": "Raw Material",
"item_name": "Bearing Pipe"
},
{
"default_supplier": "New World Realty",
"item_defaults": [{
"default_warehouse": "Stores"
}],
"description": "1/32 in. x 24 in. x 47 in. HDPE Opaque Sheet",
"image": null,
"item_code": "Wing Sheet",
"item_group": "Raw Material",
"item_name": "Wing Sheet"
},
{
"default_supplier": "Eagle Hardware",
"item_defaults": [{
"default_warehouse": "Stores"
}],
"description": "3/16 in. x 6 in. x 6 in. Low Carbon Steel Plate",
"image": null,
"item_code": "Upper Bearing Plate",
"item_group": "Raw Material",
"item_name": "Upper Bearing Plate"
},
{
"default_supplier": "Asiatic Solutions",
"item_defaults": [{
"default_warehouse": "Stores"
}],
"description": "Bearing Assembly",
"image": null,
"item_code": "Bearing Assembly",
"item_group": "Sub Assemblies",
"item_name": "Bearing Assembly"
},
{
"default_supplier": "HomeBase",
"item_defaults": [{
"default_warehouse": "Stores"
}],
"description": "3/4 in. x 2 ft. x 4 ft. Pine Plywood",
"image": null,
"item_code": "Base Plate",
"item_group": "Raw Material",
"item_name": "Base Plate",
"is_sub_contracted_item": 1
},
{
"default_supplier": "Scott Ties",
"item_defaults": [{
"default_warehouse": "Stores"
}],
"description": "N/A",
"image": null,
"item_code": "Stand",
"item_group": "Raw Material",
"item_name": "Stand"
},
{
"default_supplier": "Eagle Hardware",
"item_defaults": [{
"default_warehouse": "Stores"
}],
"description": "1 in. x 3 in. x 1 ft. Multipurpose Al Alloy Bar",
"image": null,
"item_code": "Bearing Collar",
"item_group": "Raw Material",
"item_name": "Bearing Collar"
},
{
"default_supplier": "Eagle Hardware",
"item_defaults": [{
"default_warehouse": "Stores"
}],
"description": "1/4 in. x 6 in. x 6 in. Mild Steel Plate",
"image": null,
"item_code": "Base Bearing Plate",
"item_group": "Raw Material",
"item_name": "Base Bearing Plate"
},
{
"default_supplier": "HomeBase",
"item_defaults": [{
"default_warehouse": "Stores"
}],
"description": "15/32 in. x 4 ft. x 8 ft. 3-Ply Rtd Sheathing",
"image": null,
"item_code": "External Disc",
"item_group": "Raw Material",
"item_name": "External Disc"
},
{
"default_supplier": "Eagle Hardware",
"item_defaults": [{
"default_warehouse": "Stores"
}],
"description": "1.25 in. Diameter x 6 ft. Mild Steel Tubing",
"image": null,
"item_code": "Shaft",
"item_group": "Raw Material",
"item_name": "Shaft"
},
{
"default_supplier": "Ks Merchandise",
"item_defaults": [{
"default_warehouse": "Stores"
}],
"description": "1/2 in. x 2 ft. x 4 ft. Pine Plywood",
"image": null,
"item_code": "Blade Rib",
"item_group": "Raw Material",
"item_name": "Blade Rib"
},
{
"default_supplier": "HomeBase",
"item_defaults": [{
"default_warehouse": "Stores"
}],
"description": "For Bearing Collar",
"image": null,
"item_code": "Internal Disc",
"item_group": "Raw Material",
"item_name": "Internal Disc"
},
{
"default_supplier": null,
"item_defaults": [{
"default_warehouse": "Finished Goods"
}],
"description": "Small Wind Turbine for Home Use\n\n\n<!-- html -->\n<p>Size: Small</p>",
"image": "/assets/erpnext_demo/images/wind-turbine-1.jpg",
"item_code": "Wind Turbine-S",
"item_group": "Products",
"item_name": "Wind Turbine-S",
"variant_of": "Wind Turbine",
"valuation_rate": 300,
"attributes":[
{
"attribute": "Size",
"attribute_value": "Small"
}
]
},
{
"default_supplier": null,
"item_defaults": [{
"default_warehouse": "Finished Goods"
}],
"description": "Small Wind Turbine for Home Use\n\n\n<!-- html -->\n<p>Size: Medium</p>",
"image": "/assets/erpnext_demo/images/wind-turbine-1.jpg",
"item_code": "Wind Turbine-M",
"item_group": "Products",
"item_name": "Wind Turbine-M",
"variant_of": "Wind Turbine",
"valuation_rate": 300,
"attributes":[
{
"attribute": "Size",
"attribute_value": "Medium"
}
]
},
{
"default_supplier": null,
"item_defaults": [{
"default_warehouse": "Finished Goods"
}],
"description": "Small Wind Turbine for Home Use\n\n\n<!-- html -->\n<p>Size: Large</p>",
"image": "/assets/erpnext_demo/images/wind-turbine-1.jpg",
"item_code": "Wind Turbine-L",
"item_group": "Products",
"item_name": "Wind Turbine-L",
"variant_of": "Wind Turbine",
"valuation_rate": 300,
"attributes":[
{
"attribute": "Size",
"attribute_value": "Large"
}
]
},
{
"is_stock_item": 0,
"description": "Wind Mill A Series with Spare Bearing",
"item_code": "Wind Mill A Series with Spare Bearing",
"item_group": "Products",
"item_name": "Wind Mill A Series with Spare Bearing"
},
{
"default_supplier": "HomeBase",
"item_defaults": [{
"default_warehouse": "Stores"
}],
"description": "3/4 in. x 2 ft. x 4 ft. Pine Plywood",
"image": null,
"item_code": "Base Plate Un Painted",
"item_group": "Raw Material",
"item_name": "Base Plate Un Painted"
},
{
"is_fixed_asset": 1,
"asset_category": "Furnitures",
"is_stock_item": 0,
"description": "Table",
"item_code": "Table",
"item_name": "Table",
"item_group": "Products"
},
{
"is_fixed_asset": 1,
"asset_category": "Furnitures",
"is_stock_item": 0,
"description": "Chair",
"item_code": "Chair",
"item_name": "Chair",
"item_group": "Products"
},
{
"is_fixed_asset": 1,
"asset_category": "Electronic Equipments",
"is_stock_item": 0,
"description": "Computer",
"item_code": "Computer",
"item_name": "Computer",
"item_group": "Products"
},
{
"is_fixed_asset": 1,
"asset_category": "Electronic Equipments",
"is_stock_item": 0,
"description": "Mobile",
"item_code": "Mobile",
"item_name": "Mobile",
"item_group": "Products"
},
{
"is_fixed_asset": 1,
"asset_category": "Softwares",
"is_stock_item": 0,
"description": "ERP",
"item_code": "ERP",
"item_name": "ERP",
"item_group": "All Item Groups"
},
{
"is_fixed_asset": 1,
"asset_category": "Softwares",
"is_stock_item": 0,
"description": "Autocad",
"item_code": "Autocad",
"item_name": "Autocad",
"item_group": "All Item Groups"
},
{
"is_stock_item": 1,
"has_batch_no": 1,
"create_new_batch": 1,
"valuation_rate": 200,
"item_defaults": [{
"default_warehouse": "Stores"
}],
"description": "Corrugated Box",
"item_code": "Corrugated Box",
"item_name": "Corrugated Box",
"item_group": "All Item Groups"
}
{
"item_defaults": [
{
"default_supplier": "Asiatic Solutions",
"default_warehouse": "Stores"
}
],
"description": "For Upper Bearing",
"image": "/assets/erpnext_demo/images/disc.png",
"item_code": "Disc Collars",
"item_group": "Raw Material",
"item_name": "Disc Collars"
},
{
"item_defaults": [
{
"default_supplier": "Nan Duskin",
"default_warehouse": "Stores"
}
],
"description": "CAST IRON, MCMASTER PART NO. 3710T13",
"image": "/assets/erpnext_demo/images/bearing.jpg",
"item_code": "Bearing Block",
"item_group": "Raw Material",
"item_name": "Bearing Block"
},
{
"item_defaults": [
{
"default_supplier": null,
"default_warehouse": "Finished Goods"
}
],
"description": "Wind Mill C Series for Commercial Use 18ft",
"image": "/assets/erpnext_demo/images/wind-turbine-2.png",
"item_code": "Wind MIll C Series",
"item_group": "Products",
"item_name": "Wind MIll C Series"
},
{
"item_defaults": [
{
"default_supplier": null,
"default_warehouse": "Finished Goods"
}
],
"description": "Wind Mill A Series for Home Use 9ft",
"image": "/assets/erpnext_demo/images/wind-turbine.png",
"item_code": "Wind Mill A Series",
"item_group": "Products",
"item_name": "Wind Mill A Series"
},
{
"item_defaults": [
{
"default_supplier": null,
"default_warehouse": "Finished Goods"
}
],
"description": "Small Wind Turbine for Home Use\n\n\n<!-- html -->",
"image": "/assets/erpnext_demo/images/wind-turbine-1.jpg",
"item_code": "Wind Turbine",
"item_group": "Products",
"item_name": "Wind Turbine",
"has_variants": 1,
"has_serial_no": 1,
"attributes": [
{
"attribute": "Size"
}
]
},
{
"item_defaults": [
{
"default_supplier": "HomeBase",
"default_warehouse": "Stores"
}
],
"description": "1.5 in. Diameter x 36 in. Mild Steel Tubing",
"image": null,
"item_code": "Bearing Pipe",
"item_group": "Raw Material",
"item_name": "Bearing Pipe"
},
{
"item_defaults": [
{
"default_supplier": "New World Realty",
"default_warehouse": "Stores"
}
],
"description": "1/32 in. x 24 in. x 47 in. HDPE Opaque Sheet",
"image": null,
"item_code": "Wing Sheet",
"item_group": "Raw Material",
"item_name": "Wing Sheet"
},
{
"item_defaults": [
{
"default_supplier": "Eagle Hardware",
"default_warehouse": "Stores"
}
],
"description": "3/16 in. x 6 in. x 6 in. Low Carbon Steel Plate",
"image": null,
"item_code": "Upper Bearing Plate",
"item_group": "Raw Material",
"item_name": "Upper Bearing Plate"
},
{
"item_defaults": [
{
"default_supplier": "Asiatic Solutions",
"default_warehouse": "Stores"
}
],
"description": "Bearing Assembly",
"image": null,
"item_code": "Bearing Assembly",
"item_group": "Sub Assemblies",
"item_name": "Bearing Assembly"
},
{
"item_defaults": [
{
"default_supplier": "HomeBase",
"default_warehouse": "Stores"
}
],
"description": "3/4 in. x 2 ft. x 4 ft. Pine Plywood",
"image": null,
"item_code": "Base Plate",
"item_group": "Raw Material",
"item_name": "Base Plate",
"is_sub_contracted_item": 1
},
{
"item_defaults": [
{
"default_supplier": "Scott Ties",
"default_warehouse": "Stores"
}
],
"description": "N/A",
"image": null,
"item_code": "Stand",
"item_group": "Raw Material",
"item_name": "Stand"
},
{
"item_defaults": [
{
"default_supplier": "Eagle Hardware",
"default_warehouse": "Stores"
}
],
"description": "1 in. x 3 in. x 1 ft. Multipurpose Al Alloy Bar",
"image": null,
"item_code": "Bearing Collar",
"item_group": "Raw Material",
"item_name": "Bearing Collar"
},
{
"item_defaults": [
{
"default_supplier": "Eagle Hardware",
"default_warehouse": "Stores"
}
],
"description": "1/4 in. x 6 in. x 6 in. Mild Steel Plate",
"image": null,
"item_code": "Base Bearing Plate",
"item_group": "Raw Material",
"item_name": "Base Bearing Plate"
},
{
"item_defaults": [
{
"default_supplier": "HomeBase",
"default_warehouse": "Stores"
}
],
"description": "15/32 in. x 4 ft. x 8 ft. 3-Ply Rtd Sheathing",
"image": null,
"item_code": "External Disc",
"item_group": "Raw Material",
"item_name": "External Disc"
},
{
"item_defaults": [
{
"default_supplier": "Eagle Hardware",
"default_warehouse": "Stores"
}
],
"description": "1.25 in. Diameter x 6 ft. Mild Steel Tubing",
"image": null,
"item_code": "Shaft",
"item_group": "Raw Material",
"item_name": "Shaft"
},
{
"item_defaults": [
{
"default_supplier": "Ks Merchandise",
"default_warehouse": "Stores"
}
],
"description": "1/2 in. x 2 ft. x 4 ft. Pine Plywood",
"image": null,
"item_code": "Blade Rib",
"item_group": "Raw Material",
"item_name": "Blade Rib"
},
{
"item_defaults": [
{
"default_supplier": "HomeBase",
"default_warehouse": "Stores"
}
],
"description": "For Bearing Collar",
"image": null,
"item_code": "Internal Disc",
"item_group": "Raw Material",
"item_name": "Internal Disc"
},
{
"item_defaults": [
{
"default_supplier": null,
"default_warehouse": "Finished Goods"
}
],
"description": "Small Wind Turbine for Home Use\n\n\n<!-- html -->\n<p>Size: Small</p>",
"image": "/assets/erpnext_demo/images/wind-turbine-1.jpg",
"item_code": "Wind Turbine-S",
"item_group": "Products",
"item_name": "Wind Turbine-S",
"variant_of": "Wind Turbine",
"valuation_rate": 300,
"attributes": [
{
"attribute": "Size",
"attribute_value": "Small"
}
]
},
{
"item_defaults": [
{
"default_supplier": null,
"default_warehouse": "Finished Goods"
}
],
"description": "Small Wind Turbine for Home Use\n\n\n<!-- html -->\n<p>Size: Medium</p>",
"image": "/assets/erpnext_demo/images/wind-turbine-1.jpg",
"item_code": "Wind Turbine-M",
"item_group": "Products",
"item_name": "Wind Turbine-M",
"variant_of": "Wind Turbine",
"valuation_rate": 300,
"attributes": [
{
"attribute": "Size",
"attribute_value": "Medium"
}
]
},
{
"item_defaults": [
{
"default_supplier": null,
"default_warehouse": "Finished Goods"
}
],
"description": "Small Wind Turbine for Home Use\n\n\n<!-- html -->\n<p>Size: Large</p>",
"image": "/assets/erpnext_demo/images/wind-turbine-1.jpg",
"item_code": "Wind Turbine-L",
"item_group": "Products",
"item_name": "Wind Turbine-L",
"variant_of": "Wind Turbine",
"valuation_rate": 300,
"attributes": [
{
"attribute": "Size",
"attribute_value": "Large"
}
]
},
{
"is_stock_item": 0,
"description": "Wind Mill A Series with Spare Bearing",
"item_code": "Wind Mill A Series with Spare Bearing",
"item_group": "Products",
"item_name": "Wind Mill A Series with Spare Bearing"
},
{
"item_defaults": [
{
"default_supplier": "HomeBase",
"default_warehouse": "Stores"
}
],
"description": "3/4 in. x 2 ft. x 4 ft. Pine Plywood",
"image": null,
"item_code": "Base Plate Un Painted",
"item_group": "Raw Material",
"item_name": "Base Plate Un Painted"
},
{
"is_fixed_asset": 1,
"asset_category": "Furnitures",
"is_stock_item": 0,
"description": "Table",
"item_code": "Table",
"item_name": "Table",
"item_group": "Products"
},
{
"is_fixed_asset": 1,
"asset_category": "Furnitures",
"is_stock_item": 0,
"description": "Chair",
"item_code": "Chair",
"item_name": "Chair",
"item_group": "Products"
},
{
"is_fixed_asset": 1,
"asset_category": "Electronic Equipments",
"is_stock_item": 0,
"description": "Computer",
"item_code": "Computer",
"item_name": "Computer",
"item_group": "Products"
},
{
"is_fixed_asset": 1,
"asset_category": "Electronic Equipments",
"is_stock_item": 0,
"description": "Mobile",
"item_code": "Mobile",
"item_name": "Mobile",
"item_group": "Products"
},
{
"is_fixed_asset": 1,
"asset_category": "Softwares",
"is_stock_item": 0,
"description": "ERP",
"item_code": "ERP",
"item_name": "ERP",
"item_group": "All Item Groups"
},
{
"is_fixed_asset": 1,
"asset_category": "Softwares",
"is_stock_item": 0,
"description": "Autocad",
"item_code": "Autocad",
"item_name": "Autocad",
"item_group": "All Item Groups"
},
{
"is_stock_item": 1,
"has_batch_no": 1,
"create_new_batch": 1,
"valuation_rate": 200,
"item_defaults": [
{
"default_warehouse": "Stores"
}
],
"description": "Corrugated Box",
"item_code": "Corrugated Box",
"item_name": "Corrugated Box",
"item_group": "All Item Groups"
},
{
"item_defaults": [
{
"default_warehouse": "Finished Goods"
}
],
"is_stock_item": 1,
"description": "OnePlus 6",
"item_code": "OnePlus 6",
"item_name": "OnePlus 6",
"item_group": "Products",
"domain": "Retail"
},
{
"item_defaults": [
{
"default_warehouse": "Finished Goods"
}
],
"is_stock_item": 1,
"description": "OnePlus 6T",
"item_code": "OnePlus 6T",
"item_name": "OnePlus 6T",
"item_group": "Products",
"domain": "Retail"
},
{
"item_defaults": [
{
"default_warehouse": "Finished Goods"
}
],
"is_stock_item": 1,
"description": "Xiaomi Poco F1",
"item_code": "Xiaomi Poco F1",
"item_name": "Xiaomi Poco F1",
"item_group": "Products",
"domain": "Retail"
},
{
"item_defaults": [
{
"default_warehouse": "Finished Goods"
}
],
"is_stock_item": 1,
"description": "Iphone XS",
"item_code": "Iphone XS",
"item_name": "Iphone XS",
"item_group": "Products",
"domain": "Retail"
},
{
"item_defaults": [
{
"default_warehouse": "Finished Goods"
}
],
"is_stock_item": 1,
"description": "Samsung Galaxy S9",
"item_code": "Samsung Galaxy S9",
"item_name": "Samsung Galaxy S9",
"item_group": "Products",
"domain": "Retail"
},
{
"item_defaults": [
{
"default_warehouse": "Finished Goods"
}
],
"is_stock_item": 1,
"description": "Sony Bluetooth Headphone",
"item_code": "Sony Bluetooth Headphone",
"item_name": "Sony Bluetooth Headphone",
"item_group": "Products",
"domain": "Retail"
},
{
"is_stock_item": 0,
"description": "Samsung Phone Repair",
"item_code": "Samsung Phone Repair",
"item_name": "Samsung Phone Repair",
"item_group": "Services",
"domain": "Retail"
},
{
"is_stock_item": 0,
"description": "OnePlus Phone Repair",
"item_code": "OnePlus Phone Repair",
"item_name": "OnePlus Phone Repair",
"item_group": "Services",
"domain": "Retail"
},
{
"is_stock_item": 0,
"description": "Xiaomi Phone Repair",
"item_code": "Xiaomi Phone Repair",
"item_name": "Xiaomi Phone Repair",
"item_group": "Services",
"domain": "Retail"
},
{
"is_stock_item": 0,
"description": "Apple Phone Repair",
"item_code": "Apple Phone Repair",
"item_name": "Apple Phone Repair",
"item_group": "Services",
"domain": "Retail"
}
]

View File

@@ -5,104 +5,104 @@
"last_name": "User"
},
{
"email": "DikmanShervashidze@example.com",
"first_name": "Dikman",
"last_name": "Shervashidze"
"email": "DianaPrince@example.com",
"first_name": "Diana",
"last_name": "Prince"
},
{
"email": "Zukutakitoteka@example.com",
"first_name": "Zukutakitoteka",
"last_name": null
"email": "ZatannaZatara@example.com",
"first_name": "Zatanna",
"last_name": "Zatara"
},
{
"email": "HatsueKashiwagi@example.com",
"first_name": "Hatsue",
"last_name": "Kashiwagi"
"email": "HollyGranger@example.com",
"first_name": "Holly",
"last_name": "Granger"
},
{
"email": "NuranVerkleij@example.com",
"first_name": "Nuran",
"last_name": "Verkleij"
"email": "NeptuniaAquaria@example.com",
"first_name": "Neptunia",
"last_name": "Aquaria"
},
{
"email": "aromn@example.com",
"first_name": "Arom",
"last_name": "Nolan"
"email": "ArthurCurry@example.com",
"first_name": "Arthur",
"last_name": "Curry"
},
{
"email": "TildeLindqvist@example.com",
"first_name": "Tilde",
"last_name": "Lindqvist"
"email": "ThaliaAlGhul@example.com",
"first_name": "Thalia",
"last_name": "Al Ghul"
},
{
"email": "MichalSobczak@example.com",
"first_name": "Micha\u0142",
"last_name": "Sobczak"
"email": "MaxwellLord@example.com",
"first_name": "Maxwell",
"last_name": "Lord"
},
{
"email": "GabrielleLoftus@example.com",
"first_name": "Gabrielle",
"last_name": "Loftus"
"email": "GraceChoi@example.com",
"first_name": "Grace",
"last_name": "Choi"
},
{
"email": "VakhitaRyzaev@example.com",
"first_name": "Vakhita",
"last_name": "Ryzaev"
"email": "VandalSavage@example.com",
"first_name": "Vandal",
"last_name": "Savage"
},
{
"email": "CharmaineGaudreau@example.com",
"first_name": "Charmaine",
"last_name": "Gaudreau"
"email": "CaitlinSnow@example.com",
"first_name": "Caitlin",
"last_name": "Snow"
},
{
"email": "RafaelaMaartens@example.com",
"first_name": "Rafa\u00ebla",
"last_name": "Maartens"
"email": "RipHunter@example.com",
"first_name": "Rip",
"last_name": "Hunter"
},
{
"email": "NuguseYohannes@example.com",
"first_name": "Nuguse",
"last_name": "Yohannes"
"email": "NicholasFury@example.com",
"first_name": "Nicholas",
"last_name": "Fury"
},
{
"email": "panca@example.com",
"first_name": "\u0420\u0430\u0438\u0441\u0430",
"last_name": "\u0411\u0435\u043b\u044f\u043a\u043e\u0432\u0430"
"email": "PeterParker@example.com",
"first_name": "Peter",
"last_name": "Parker"
},
{
"email": "CaYinLong@example.com",
"first_name": "\u80e4\u9686",
"last_name": "\u8521"
"email": "JohnConstantine@example.com",
"first_name": "John",
"last_name": "Constantine"
},
{
"email": "FreddieScott@example.com",
"first_name": "Freddie",
"last_name": "Scott"
"email": "HalJordan@example.com",
"first_name": "Hal",
"last_name": "Jordan"
},
{
"email": "BergoraVigfusdottir@example.com",
"first_name": "Berg\u00fe\u00f3ra",
"last_name": "Vigf\u00fasd\u00f3ttir"
"email": "VictorStone@example.com",
"first_name": "Victor",
"last_name": "Stone"
},
{
"email": "WardNajmalDinKalb@example.com",
"first_name": "Ward",
"last_name": "Kalb"
"email": "BruceWayne@example.com",
"first_name": "Bruce",
"last_name": "Wayne"
},
{
"email": "WanMai@example.com",
"first_name": "Wan",
"last_name": "Mai"
"email": "ClarkKent@example.com",
"first_name": "Clark",
"last_name": "Kent"
},
{
"email": "LeonAbdulov@example.com",
"first_name": "Leon",
"last_name": "Abdulov"
"email": "BarryAllen@example.com",
"first_name": "Barry",
"last_name": "Allen"
},
{
"email": "SabinaNovotna@example.com",
"first_name": "Sabina",
"last_name": "Novotn\u00e1"
"email": "KaraZorEl@example.com",
"first_name": "Kara",
"last_name": "Zor El"
},
{
"email": "demo@erpnext.com",

View File

@@ -3,8 +3,9 @@ from __future__ import unicode_literals
import frappe, sys
import erpnext
import frappe.utils
from erpnext.demo.user import hr, sales, purchase, manufacturing, stock, accounts, projects, fixed_asset, education
from erpnext.demo.setup import education, manufacture, setup_data, healthcare
from erpnext.demo.user import hr, sales, purchase, manufacturing, stock, accounts, projects, fixed_asset
from erpnext.demo.user import education as edu
from erpnext.demo.setup import education, manufacture, setup_data, healthcare, retail
"""
Make a demo
@@ -28,6 +29,8 @@ def make(domain='Manufacturing', days=100):
setup_data.setup(domain)
if domain== 'Manufacturing':
manufacture.setup_data()
elif domain == "Retail":
retail.setup_data()
elif domain== 'Education':
education.setup_data()
elif domain== 'Healthcare':
@@ -77,13 +80,13 @@ def simulate(domain='Manufacturing', days=100):
stock.work()
accounts.work()
projects.run_projects(current_date)
sales.work(domain)
# run_messages()
if domain=='Manufacturing':
sales.work()
manufacturing.work()
elif domain=='Education':
education.work()
edu.work()
except:
frappe.db.set_global('demo_last_date', current_date)

View File

@@ -5,7 +5,7 @@ data = {
'company_name': 'Wind Power LLC'
},
'Retail': {
'company_name': 'Annapurna Dairy Shop',
'company_name': 'Mobile Next',
},
'Distribution': {
'company_name': 'Soltice Hardware',

View File

@@ -0,0 +1,65 @@
from __future__ import unicode_literals
import random, json
import frappe
from frappe.utils import nowdate, add_days
from erpnext.demo.setup.setup_data import import_json
from erpnext.demo.domains import data
from six import iteritems
def setup_data():
setup_item()
setup_item_price()
frappe.db.commit()
frappe.clear_cache()
def setup_item():
items = json.loads(open(frappe.get_app_path('erpnext', 'demo', 'data', 'item.json')).read())
for i in items:
if not i.get("domain") == "Retail": continue
item = frappe.new_doc('Item')
item.update(i)
if hasattr(item, 'item_defaults') and item.item_defaults[0].default_warehouse:
item.item_defaults[0].company = data.get("Retail").get('company_name')
warehouse = frappe.get_all('Warehouse', filters={'warehouse_name': item.item_defaults[0].default_warehouse}, limit=1)
if warehouse:
item.item_defaults[0].default_warehouse = warehouse[0].name
item.insert()
def setup_item_price():
frappe.db.sql("delete from `tabItem Price`")
standard_selling = {
"OnePlus 6": 579,
"OnePlus 6T": 600,
"Xiaomi Poco F1": 300,
"Iphone XS": 999,
"Samsung Galaxy S9": 720,
"Sony Bluetooth Headphone": 99,
"Xiaomi Phone Repair": 10,
"Samsung Phone Repair": 20,
"OnePlus Phone Repair": 15,
"Apple Phone Repair": 30,
}
standard_buying = {
"OnePlus 6": 300,
"OnePlus 6T": 350,
"Xiaomi Poco F1": 200,
"Iphone XS": 600,
"Samsung Galaxy S9": 500,
"Sony Bluetooth Headphone": 69
}
for price_list in ("standard_buying", "standard_selling"):
for item, rate in iteritems(locals().get(price_list)):
frappe.get_doc({
"doctype": "Item Price",
"price_list": price_list.replace("_", " ").title(),
"item_code": item,
"selling": 1 if price_list=="standard_selling" else 0,
"buying": 1 if price_list=="standard_buying" else 0,
"price_list_rate": rate,
"currency": "USD"
}).insert()

View File

@@ -5,6 +5,7 @@ import frappe, erpnext
from frappe.utils.nestedset import get_root_of
from frappe.utils import flt, now_datetime, cstr, random_string
from frappe.utils.make_random import add_random_children, get_random
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
from erpnext.demo.domains import data
from frappe import _
@@ -14,9 +15,10 @@ def setup(domain):
setup_fiscal_year()
setup_holiday_list()
setup_user()
#setup_employee()
setup_employee()
setup_user_roles()
setup_role_permissions()
setup_custom_field_for_domain()
employees = frappe.get_all('Employee', fields=['name', 'date_of_joining'])
@@ -120,7 +122,7 @@ def setup_user():
user = frappe.new_doc("User")
user.update(u)
user.flags.no_welcome_mail = True
user.new_password = 'demo'
user.new_password = 'Demo1234567!!!'
user.insert()
def setup_employee():
@@ -136,6 +138,8 @@ def setup_employee():
salary_component.save()
import_json('Employee')
holiday_list = frappe.db.get_value("Holiday List", {"holiday_list_name": str(now_datetime().year)}, 'name')
frappe.db.sql('''update tabEmployee set holiday_list={0}'''.format(holiday_list))
def setup_salary_structure(employees, salary_slip_based_on_timesheet=0):
ss = frappe.new_doc('Salary Structure')
@@ -166,12 +170,16 @@ def setup_salary_structure(employees, salary_slip_based_on_timesheet=0):
"idx": 1
})
ss.insert()
ss.submit()
for e in employees:
sa = frappe.new_doc("Salary Structure Assignment")
sa.employee = e.name
sa.salary_structure = ss.name
sa.from_date = "2015-01-01"
sa.base = random.random() * 10000
sa.insert()
sa.submit()
return ss
@@ -184,52 +192,63 @@ def setup_user_roles():
'Nursing User', 'Patient')
if not frappe.db.get_global('demo_hr_user'):
user = frappe.get_doc('User', 'CharmaineGaudreau@example.com')
user = frappe.get_doc('User', 'CaitlinSnow@example.com')
user.add_roles('HR User', 'HR Manager', 'Accounts User')
frappe.db.set_global('demo_hr_user', user.name)
update_employee_department(user.name, 'Human Resources')
for d in frappe.get_all('User Permission', filters={"user": "CaitlinSnow@example.com"}):
frappe.delete_doc('User Permission', d.name)
if not frappe.db.get_global('demo_sales_user_1'):
user = frappe.get_doc('User', 'VakhitaRyzaev@example.com')
user = frappe.get_doc('User', 'VandalSavage@example.com')
user.add_roles('Sales User')
update_employee_department(user.name, 'Sales')
frappe.db.set_global('demo_sales_user_1', user.name)
if not frappe.db.get_global('demo_sales_user_2'):
user = frappe.get_doc('User', 'GabrielleLoftus@example.com')
user = frappe.get_doc('User', 'GraceChoi@example.com')
user.add_roles('Sales User', 'Sales Manager', 'Accounts User')
update_employee_department(user.name, 'Sales')
frappe.db.set_global('demo_sales_user_2', user.name)
if not frappe.db.get_global('demo_purchase_user'):
user = frappe.get_doc('User', 'MichalSobczak@example.com')
user = frappe.get_doc('User', 'MaxwellLord@example.com')
user.add_roles('Purchase User', 'Purchase Manager', 'Accounts User', 'Stock User')
update_employee_department(user.name, 'Purchase')
frappe.db.set_global('demo_purchase_user', user.name)
if not frappe.db.get_global('demo_manufacturing_user'):
user = frappe.get_doc('User', 'NuranVerkleij@example.com')
user = frappe.get_doc('User', 'NeptuniaAquaria@example.com')
user.add_roles('Manufacturing User', 'Stock User', 'Purchase User', 'Accounts User')
update_employee_department(user.name, 'Production')
frappe.db.set_global('demo_manufacturing_user', user.name)
if not frappe.db.get_global('demo_stock_user'):
user = frappe.get_doc('User', 'HatsueKashiwagi@example.com')
user = frappe.get_doc('User', 'HollyGranger@example.com')
user.add_roles('Manufacturing User', 'Stock User', 'Purchase User', 'Accounts User')
update_employee_department(user.name, 'Production')
frappe.db.set_global('demo_stock_user', user.name)
if not frappe.db.get_global('demo_accounts_user'):
user = frappe.get_doc('User', 'LeonAbdulov@example.com')
user = frappe.get_doc('User', 'BarryAllen@example.com')
user.add_roles('Accounts User', 'Accounts Manager', 'Sales User', 'Purchase User')
update_employee_department(user.name, 'Accounts')
frappe.db.set_global('demo_accounts_user', user.name)
if not frappe.db.get_global('demo_projects_user'):
user = frappe.get_doc('User', 'panca@example.com')
user = frappe.get_doc('User', 'PeterParker@example.com')
user.add_roles('HR User', 'Projects User')
update_employee_department(user.name, 'Management')
frappe.db.set_global('demo_projects_user', user.name)
if not frappe.db.get_global('demo_education_user'):
user = frappe.get_doc('User', 'aromn@example.com')
user = frappe.get_doc('User', 'ArthurCurry@example.com')
user.add_roles('Academics User')
update_employee_department(user.name, 'Management')
frappe.db.set_global('demo_education_user', user.name)
#Add Expense Approver
user = frappe.get_doc('User', 'WanMai@example.com')
user = frappe.get_doc('User', 'ClarkKent@example.com')
user.add_roles('Expense Approver')
def setup_leave_allocation():
@@ -403,3 +422,19 @@ def import_json(doctype, submit=False, values=None):
frappe.db.commit()
frappe.flags.in_import = False
def update_employee_department(user_id, department):
employee = frappe.db.get_value('Employee', {"user_id": user_id}, 'name')
department = frappe.db.get_value('Department', {'department_name': department}, 'name')
frappe.db.set_value('Employee', employee, 'department', department)
def setup_custom_field_for_domain():
field = {
"Item": [
dict(fieldname='domain', label='Domain',
fieldtype='Select', hidden=1, default="Manufacturing",
options="Manufacturing\nService\nDistribution\nRetail"
)
]
}
create_custom_fields(field)

View File

@@ -56,7 +56,7 @@ def work():
if random.random() < 0.5:
make_payment_entries("Purchase Invoice", "Accounts Payable")
if random.random() < 0.1:
if random.random() < 0.4:
#make payment request against sales invoice
sales_invoice_name = get_random("Sales Invoice", filters={"docstatus": 1})
if sales_invoice_name:

View File

@@ -14,34 +14,31 @@ from erpnext.hr.doctype.leave_application.leave_application import (get_leave_ba
def work():
frappe.set_user(frappe.db.get_global('demo_hr_user'))
year, month = frappe.flags.current_date.strftime("%Y-%m").split("-")
setup_department_approvers()
mark_attendance()
make_leave_application()
# payroll entry
if not frappe.db.sql('select name from `tabSalary Slip` where month(adddate(start_date, interval 1 month))=month(curdate())'):
# process payroll for previous month
payroll_entry = frappe.new_doc("Payroll Entry")
payroll_entry.company = frappe.flags.company
payroll_entry.payroll_frequency = 'Monthly'
# select a posting date from the previous month
payroll_entry.posting_date = get_last_day(getdate(frappe.flags.current_date) - datetime.timedelta(days=10))
payroll_entry.payment_account = frappe.get_value('Account', {'account_type': 'Cash', 'company': erpnext.get_default_company(),'is_group':0}, "name")
payroll_entry.set_start_end_dates()
# based on frequency
payroll_entry = get_payroll_entry()
payroll_entry.salary_slip_based_on_timesheet = 0
payroll_entry.save()
payroll_entry.create_salary_slips()
payroll_entry.submit_salary_slips()
payroll_entry.make_accrual_jv_entry()
payroll_entry.submit()
# payroll_entry.make_journal_entry(reference_date=frappe.flags.current_date,
# reference_number=random_string(10))
# based on timesheet
payroll_entry = get_payroll_entry()
payroll_entry.salary_slip_based_on_timesheet = 1
payroll_entry.save()
payroll_entry.create_salary_slips()
payroll_entry.submit_salary_slips()
payroll_entry.make_accrual_jv_entry()
payroll_entry.submit()
# payroll_entry.make_journal_entry(reference_date=frappe.flags.current_date,
# reference_number=random_string(10))
@@ -55,12 +52,14 @@ def work():
expense_claim.company = frappe.flags.company
expense_claim.payable_account = get_payable_account(expense_claim.company)
expense_claim.posting_date = frappe.flags.current_date
expense_claim.insert()
expense_claim.expense_approver = frappe.db.get_global('demo_hr_user')
expense_claim.save()
rand = random.random()
if rand < 0.4:
update_sanctioned_amount(expense_claim)
expense_claim.approval_status = 'Approved'
expense_claim.submit()
if random.randint(0, 1):
@@ -72,6 +71,19 @@ def work():
je.flags.ignore_permissions = 1
je.submit()
def get_payroll_entry():
# process payroll for previous month
payroll_entry = frappe.new_doc("Payroll Entry")
payroll_entry.company = frappe.flags.company
payroll_entry.payroll_frequency = 'Monthly'
# select a posting date from the previous month
payroll_entry.posting_date = get_last_day(getdate(frappe.flags.current_date) - datetime.timedelta(days=10))
payroll_entry.payment_account = frappe.get_value('Account', {'account_type': 'Cash', 'company': erpnext.get_default_company(),'is_group':0}, "name")
payroll_entry.set_start_end_dates()
return payroll_entry
def get_expenses():
expenses = []
expese_types = frappe.db.sql("""select ect.name, eca.default_account from `tabExpense Claim Type` ect,
@@ -114,7 +126,7 @@ def get_timesheet_based_salary_slip_employee():
def make_timesheet_records():
employees = get_timesheet_based_salary_slip_employee()
for e in employees:
ts = make_timesheet(e.employee, simulate = True, billable = 1, activity_type=get_random("Activity Type"))
ts = make_timesheet(e.employee, simulate = True, billable = 1, activity_type=get_random("Activity Type"), company=frappe.flags.company)
frappe.db.commit()
rand = random.random()
@@ -195,3 +207,11 @@ def mark_attendance():
attendance.save()
attendance.submit()
frappe.db.commit()
def setup_department_approvers():
for d in frappe.get_all('Department', filters={'department_name': ['!=', 'All Departments']}):
doc = frappe.get_doc('Department', d.name)
doc.append("leave_approvers", {'approver': frappe.session.user})
doc.append("expense_approvers", {'approver': frappe.session.user})
doc.flags.ignore_mandatory = True
doc.save()

View File

@@ -4,25 +4,32 @@
from __future__ import unicode_literals
import frappe, random, erpnext
from datetime import timedelta
from frappe.utils.make_random import how_many
from frappe.desk import query_report
from erpnext.manufacturing.doctype.workstation.workstation import WorkstationHolidayError
from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record
def work():
if random.random() < 0.3: return
frappe.set_user(frappe.db.get_global('demo_manufacturing_user'))
if not frappe.get_all('Sales Order'): return
from erpnext.projects.doctype.timesheet.timesheet import OverlapError
ppt = frappe.get_doc("Production Planning Tool", "Production Planning Tool")
ppt = frappe.new_doc("Production Plan")
ppt.company = erpnext.get_default_company()
ppt.use_multi_level_bom = 1
# ppt.use_multi_level_bom = 1 #refactored
ppt.get_items_from = "Sales Order"
ppt.purchase_request_for_warehouse = "Stores - WPL"
# ppt.purchase_request_for_warehouse = "Stores - WPL" # refactored
ppt.run_method("get_open_sales_orders")
if not ppt.get("sales_orders"): return
ppt.run_method("get_items")
ppt.run_method("raise_work_orders")
ppt.run_method("raise_material_requests")
ppt.save()
ppt.submit()
ppt.run_method("raise_work_orders")
frappe.db.commit()
# submit work orders
@@ -39,12 +46,12 @@ def work():
frappe.db.commit()
# stores -> wip
if random.random() < 0.3:
if random.random() < 0.4:
for pro in query_report.run("Open Work Orders")["result"][:how_many("Stock Entry for WIP")]:
make_stock_entry_from_pro(pro[0], "Material Transfer for Manufacture")
# wip -> fg
if random.random() < 0.3:
if random.random() < 0.4:
for pro in query_report.run("Work Orders in Progress")["result"][:how_many("Stock Entry for FG")]:
make_stock_entry_from_pro(pro[0], "Manufacture")
@@ -55,17 +62,9 @@ def work():
stock_uom = frappe.db.get_value('Item', bom.item, 'stock_uom'),
planned_start_date = frappe.flags.current_date)
# submit time logs
for timesheet in frappe.get_all("Timesheet", ["name"], {"docstatus": 0,
"work_order": ("!=", ""), "to_time": ("<", frappe.flags.current_date)}):
timesheet = frappe.get_doc("Timesheet", timesheet.name)
try:
timesheet.submit()
frappe.db.commit()
except OverlapError:
pass
except WorkstationHolidayError:
pass
# submit job card
if random.random() < 0.4:
submit_job_cards()
def make_stock_entry_from_pro(pro_id, purpose):
from erpnext.manufacturing.doctype.work_order.work_order import make_stock_entry
@@ -86,3 +85,27 @@ def make_stock_entry_from_pro(pro_id, purpose):
except (NegativeStockError, IncorrectValuationRateError, DuplicateEntryForWorkOrderError,
OperationsNotCompleteError):
frappe.db.rollback()
def submit_job_cards():
work_orders = frappe.get_all("Work Order", ["name", "creation"], {"docstatus": 1, "status": "Not Started"})
work_order = random.choice(work_orders)
# for work_order in work_orders:
start_date = work_order.creation
work_order = frappe.get_doc("Work Order", work_order.name)
job = frappe.get_all("Job Card", ["name", "operation", "work_order"],
{"docstatus": 0, "work_order": work_order.name})
if not job: return
job_map = {}
for d in job:
job_map[d.operation] = frappe.get_doc("Job Card", d.name)
for operation in work_order.operations:
job = job_map[operation.operation]
job.actual_start_date = start_date
minutes = operation.get("time_in_mins")
random_minutes = random.randint(int(minutes/2), minutes)
job.actual_end_date = job.actual_start_date + timedelta(minutes=random_minutes)
start_date = job.actual_end_date
job.save()
job.submit()

View File

@@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe
import frappe, erpnext
from frappe.utils import flt
from frappe.utils.make_random import get_random
from erpnext.projects.doctype.timesheet.test_timesheet import make_timesheet
@@ -19,7 +19,7 @@ def run_projects(current_date):
def make_timesheet_for_projects(current_date ):
for data in frappe.get_all("Task", ["name", "project"], {"status": "Open", "exp_end_date": ("<", current_date)}):
employee = get_random("Employee")
ts = make_timesheet(employee, simulate = True, billable = 1,
ts = make_timesheet(employee, simulate = True, billable = 1, company = erpnext.get_default_company(),
activity_type=get_random("Activity Type"), project=data.project, task =data.name)
if flt(ts.total_billable_amount) > 0.0:

View File

@@ -3,7 +3,7 @@
from __future__ import unicode_literals
import frappe, random
import frappe, random, json, erpnext
from frappe.utils.make_random import how_many, get_random
from frappe.desk import query_report
from erpnext.setup.utils import get_exchange_rate
@@ -16,14 +16,14 @@ from erpnext.buying.doctype.request_for_quotation.request_for_quotation import \
def work():
frappe.set_user(frappe.db.get_global('demo_purchase_user'))
if random.random() < 0.3:
if random.random() < 0.6:
report = "Items To Be Requested"
for row in query_report.run(report)["result"][:random.randint(1, 5)]:
item_code, qty = row[0], abs(row[-1])
mr = make_material_request(item_code, qty)
if random.random() < 0.3:
if random.random() < 0.6:
for mr in frappe.get_all('Material Request',
filters={'material_request_type': 'Purchase', 'status': 'Open'},
limit=random.randint(1,6)):
@@ -36,7 +36,7 @@ def work():
rfq.submit()
# Make suppier quotation from RFQ against each supplier.
if random.random() < 0.3:
if random.random() < 0.6:
for rfq in frappe.get_all('Request for Quotation',
filters={'status': 'Open'}, limit=random.randint(1, 6)):
if not frappe.get_all('Supplier Quotation',
@@ -51,15 +51,15 @@ def work():
# get supplier details
supplier = get_random("Supplier")
company_currency = frappe.get_cached_value('Company', "Wind Power LLC", "default_currency")
party_account_currency = get_party_account_currency("Supplier", supplier, "Wind Power LLC")
company_currency = frappe.get_cached_value('Company', erpnext.get_default_company(), "default_currency")
party_account_currency = get_party_account_currency("Supplier", supplier, erpnext.get_default_company())
if company_currency == party_account_currency:
exchange_rate = 1
else:
exchange_rate = get_exchange_rate(party_account_currency, company_currency, args="for_buying")
# make supplier quotations
if random.random() < 0.2:
if random.random() < 0.5:
from erpnext.stock.doctype.material_request.material_request import make_supplier_quotation
report = "Material Requests for which Supplier Quotations are not created"
@@ -80,16 +80,20 @@ def work():
report = "Requested Items To Be Ordered"
for row in query_report.run(report)["result"][:how_many("Purchase Order")]:
if row[0] != "'Total'":
po = frappe.get_doc(make_purchase_order(row[0]))
po.supplier = supplier
po.currency = party_account_currency or company_currency
po.conversion_rate = exchange_rate
po.transaction_date = frappe.flags.current_date
po.insert()
po.submit()
frappe.db.commit()
try:
po = frappe.get_doc(make_purchase_order(row[0]))
po.supplier = supplier
po.currency = party_account_currency or company_currency
po.conversion_rate = exchange_rate
po.transaction_date = frappe.flags.current_date
po.insert()
po.submit()
except Exception:
pass
else:
frappe.db.commit()
if random.random() < 0.2:
if random.random() < 0.5:
make_subcontract()
def make_material_request(item_code, qty):
@@ -122,13 +126,14 @@ def add_suppliers(rfq):
rfq.append("suppliers", { "supplier": supplier })
def make_subcontract():
from erpnext.buying.doctype.purchase_order.purchase_order import make_stock_entry
from erpnext.buying.doctype.purchase_order.purchase_order import make_rm_stock_entry
item_code = get_random("Item", {"is_sub_contracted_item": 1})
if item_code:
# make sub-contract PO
po = frappe.new_doc("Purchase Order")
po.is_subcontracted = "Yes"
po.supplier = get_random("Supplier")
po.transaction_date = frappe.flags.current_date # added
po.schedule_date = frappe.utils.add_days(frappe.flags.current_date, 7)
item_code = get_random("Item", {"is_sub_contracted_item": 1})
@@ -150,7 +155,20 @@ def make_subcontract():
make_material_request(po.items[0].item_code, po.items[0].qty)
# transfer material for sub-contract
stock_entry = frappe.get_doc(make_stock_entry(po.name, po.items[0].item_code))
rm_items = get_rm_item(po.items[0], po.supplied_items[0])
stock_entry = frappe.get_doc(make_rm_stock_entry(po.name, json.dumps([rm_items])))
stock_entry.from_warehouse = "Stores - WPL"
stock_entry.to_warehouse = "Supplier - WPL"
stock_entry.insert()
def get_rm_item(items, supplied_items):
return {
"item_code": items.get("item_code"),
"rm_item_code": supplied_items.get("rm_item_code"),
"item_name": supplied_items.get("rm_item_code"),
"qty": supplied_items.get("required_qty") + random.randint(3,10),
"amount": supplied_items.get("amount"),
"warehouse": supplied_items.get("reserve_warehouse"),
"rate": supplied_items.get("rate"),
"stock_uom": supplied_items.get("stock_uom")
}

View File

@@ -3,22 +3,23 @@
from __future__ import unicode_literals
import frappe, random
import frappe, random, erpnext
from frappe.utils import flt
from frappe.utils.make_random import add_random_children, get_random
from erpnext.setup.utils import get_exchange_rate
from erpnext.accounts.party import get_party_account_currency
from erpnext.accounts.doctype.payment_request.payment_request import make_payment_request, make_payment_entry
def work():
def work(domain="Manufacturing"):
frappe.set_user(frappe.db.get_global('demo_sales_user_2'))
if random.random() < 0.5:
for i in range(random.randint(1,7)):
make_opportunity()
if random.random() < 0.5:
for i in range(random.randint(1,3)):
make_quotation()
for i in range(random.randint(1,7)):
if random.random() < 0.5:
make_opportunity(domain)
for i in range(random.randint(1,3)):
if random.random() < 0.5:
make_quotation(domain)
# lost quotations / inquiries
if random.random() < 0.3:
@@ -32,24 +33,27 @@ def work():
if opportunity and opportunity.status in ('Open', 'Replied'):
opportunity.declare_enquiry_lost('Did not ask')
if random.random() < 0.3:
for i in range(random.randint(1,3)):
for i in range(random.randint(1,3)):
if random.random() < 0.6:
make_sales_order()
if random.random() < 0.1:
if random.random() < 0.5:
#make payment request against Sales Order
sales_order_name = get_random("Sales Order", filters={"docstatus": 1})
if sales_order_name:
so = frappe.get_doc("Sales Order", sales_order_name)
if flt(so.per_billed) != 100:
payment_request = make_payment_request(dt="Sales Order", dn=so.name, recipient_id=so.contact_email,
submit_doc=True, mute_email=True, use_dummy_message=True)
try:
if sales_order_name:
so = frappe.get_doc("Sales Order", sales_order_name)
if flt(so.per_billed) != 100:
payment_request = make_payment_request(dt="Sales Order", dn=so.name, recipient_id=so.contact_email,
submit_doc=True, mute_email=True, use_dummy_message=True)
payment_entry = frappe.get_doc(make_payment_entry(payment_request.name))
payment_entry.posting_date = frappe.flags.current_date
payment_entry.submit()
payment_entry = frappe.get_doc(make_payment_entry(payment_request.name))
payment_entry.posting_date = frappe.flags.current_date
payment_entry.submit()
except Exception:
pass
def make_opportunity():
def make_opportunity(domain):
b = frappe.get_doc({
"doctype": "Opportunity",
"enquiry_from": "Customer",
@@ -61,13 +65,13 @@ def make_opportunity():
add_random_children(b, "items", rows=4, randomize = {
"qty": (1, 5),
"item_code": ("Item", {"has_variants": 0, "is_fixed_asset": 0})
"item_code": ("Item", {"has_variants": 0, "is_fixed_asset": 0, "domain": domain})
}, unique="item_code")
b.insert()
frappe.db.commit()
def make_quotation():
def make_quotation(domain):
# get open opportunites
opportunity = get_random("Opportunity", {"status": "Open", "with_items": 1})
@@ -84,8 +88,8 @@ def make_quotation():
# get customer, currency and exchange_rate
customer = get_random("Customer")
company_currency = frappe.get_cached_value('Company', "Wind Power LLC", "default_currency")
party_account_currency = get_party_account_currency("Customer", customer, "Wind Power LLC")
company_currency = frappe.get_cached_value('Company', erpnext.get_default_company(), "default_currency")
party_account_currency = get_party_account_currency("Customer", customer, erpnext.get_default_company())
if company_currency == party_account_currency:
exchange_rate = 1
else:
@@ -104,7 +108,7 @@ def make_quotation():
add_random_children(qtn, "items", rows=3, randomize = {
"qty": (1, 5),
"item_code": ("Item", {"has_variants": "0", "is_fixed_asset": 0})
"item_code": ("Item", {"has_variants": "0", "is_fixed_asset": 0, "domain": domain})
}, unique="item_code")
qtn.insert()
@@ -115,8 +119,8 @@ def make_quotation():
def make_sales_order():
q = get_random("Quotation", {"status": "Submitted"})
if q:
from erpnext.selling.doctype.quotation.quotation import make_sales_order
so = frappe.get_doc(make_sales_order(q))
from erpnext.selling.doctype.quotation.quotation import make_sales_order as mso
so = frappe.get_doc(mso(q))
so.transaction_date = frappe.flags.current_date
so.delivery_date = frappe.utils.add_days(frappe.flags.current_date, 10)
so.insert()

View File

@@ -3,7 +3,7 @@
from __future__ import print_function, unicode_literals
import frappe, random
import frappe, random, erpnext
from frappe.desk import query_report
from erpnext.stock.stock_ledger import NegativeStockError
from erpnext.stock.doctype.serial_no.serial_no import SerialNoRequiredError, SerialNoQtyError
@@ -45,7 +45,7 @@ def make_delivery_note():
# make purchase requests
# make delivery notes (if possible)
if random.random() < 0.3:
if random.random() < 0.6:
from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note
report = "Ordered Items To Be Delivered"
for so in list(set([r[0] for r in query_report.run(report)["result"]
@@ -56,8 +56,9 @@ def make_delivery_note():
if not d.expense_account:
d.expense_account = ("Cost of Goods Sold - {0}".format(
frappe.get_cached_value('Company', dn.company, 'abbr')))
dn.insert()
try:
dn.insert()
dn.submit()
frappe.db.commit()
except (NegativeStockError, SerialNoRequiredError, SerialNoQtyError, UnableToSelectBatchError):
@@ -68,9 +69,10 @@ def make_stock_reconciliation():
from erpnext.stock.doctype.stock_reconciliation.stock_reconciliation \
import OpeningEntryAccountError, EmptyStockReconciliationItemsError
if random.random() < 0.1:
if random.random() < 0.4:
stock_reco = frappe.new_doc("Stock Reconciliation")
stock_reco.posting_date = frappe.flags.current_date
stock_reco.company = erpnext.get_default_company()
stock_reco.get_items_for("Stores - WP")
if stock_reco.items:
for item in stock_reco.items:
@@ -87,7 +89,7 @@ def make_stock_reconciliation():
def submit_draft_stock_entries():
from erpnext.stock.doctype.stock_entry.stock_entry import IncorrectValuationRateError, \
DuplicateEntryForProductionOrderError, OperationsNotCompleteError
DuplicateEntryForWorkOrderError, OperationsNotCompleteError
# try posting older drafts (if exists)
frappe.db.commit()
@@ -98,7 +100,7 @@ def submit_draft_stock_entries():
ste.save()
ste.submit()
frappe.db.commit()
except (NegativeStockError, IncorrectValuationRateError, DuplicateEntryForProductionOrderError,
except (NegativeStockError, IncorrectValuationRateError, DuplicateEntryForWorkOrderError,
OperationsNotCompleteError):
frappe.db.rollback()

View File

@@ -5,6 +5,9 @@ data = {
'Patient Encounter',
'Lab Test',
'Healthcare',
'Vital Signs',
'Clinical Procedure',
'Inpatient Record',
'Accounts',
'Buying',
'Stock',

View File

@@ -4,7 +4,29 @@
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import get_link_to_form
from frappe.model.document import Document
class StudentLeaveApplication(Document):
pass
def validate(self):
self.validate_duplicate()
def validate_duplicate(self):
data = frappe.db.sql(""" select name from `tabStudent Leave Application`
where
((%(from_date)s > from_date and %(from_date)s < to_date) or
(%(to_date)s > from_date and %(to_date)s < to_date) or
(%(from_date)s <= from_date and %(to_date)s >= to_date)) and
name != %(name)s and student = %(student)s and docstatus < 2
""", {
'from_date': self.from_date,
'to_date': self.to_date,
'student': self.student,
'name': self.name
}, as_dict=1)
if data:
link = get_link_to_form("Student Leave Application", data[0].name)
frappe.throw(_("Leave application {0} already exists against the student {1}")
.format(link, self.student))

View File

@@ -0,0 +1,71 @@
// Copyright (c) 2018, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('QuickBooks Migrator', {
connect: function(frm) {
// OAuth requires user intervention to provide application access permissionsto requested scope
// Here we open a new window and redirect user to the authorization url.
// After user grants us permission to access. We will set authorization details on this doc which will force refresh.
window.open(frm.doc.authorization_url)
},
fetch_data: function(frm) {
frm.call("migrate")
},
onload: function(frm) {
frm.trigger("set_indicator")
var domain = frappe.urllib.get_base_url()
var redirect_url = `${domain}/api/method/erpnext.erpnext_integrations.doctype.quickbooks_migrator.quickbooks_migrator.callback`
if (frm.doc.redirect_url != redirect_url) {
frm.set_value("redirect_url", redirect_url)
}
// Instead of changing percentage width and message of single progress bar
// Show a different porgress bar for every action after some time remove the finished progress bar
// Former approach causes the progress bar to dance back and forth.
frm.trigger("set_indicator")
frappe.realtime.on("quickbooks_progress_update", function (data) {
frm.dashboard.show_progress(data.message, (data.count / data.total) * 100, data.message)
if (data.count == data.total) {
window.setTimeout( function(message) {frm.dashboard.hide_progress(message)}, 1500, data.messsage)
}
})
},
refresh: function(frm) {
frm.trigger("set_indicator")
if (!frm.doc.access_token) {
// Unset access_token signifies that we don't have enough information to connect to quickbooks api and fetch data
if (frm.doc.authorization_url) {
frm.add_custom_button(__("Connect to Quickbooks"), function () {
frm.trigger("connect")
});
}
}
if (frm.doc.access_token) {
// If we have access_token that means we also have refresh_token we don't need user intervention anymore
// All we need now is a Company from erpnext
frm.remove_custom_button(__("Connect to Quickbooks"))
frm.toggle_display("company_settings", 1)
frm.set_df_property("company", "reqd", 1)
if (frm.doc.company) {
frm.add_custom_button(__("Fetch Data"), function () {
frm.trigger("fetch_data")
});
}
}
},
set_indicator: function(frm) {
var indicator_map = {
"Connecting to QuickBooks": [__("Connecting to QuickBooks"), "orange"],
"Connected to QuickBooks": [__("Connected to QuickBooks"), "green"],
"In Progress": [__("In Progress"), "orange"],
"Complete": [__("Complete"), "green"],
"Failed": [__("Failed"), "red"],
}
if (frm.doc.status) {
var indicator = indicator_map[frm.doc.status]
var label = indicator[0]
var color = indicator[1]
frm.page.set_indicator(label, color)
}
},
});

View File

@@ -0,0 +1,843 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 1,
"creation": "2018-07-10 14:48:16.757030",
"custom": 0,
"docstatus": 0,
"doctype": "DocType",
"document_type": "",
"editable_grid": 1,
"engine": "InnoDB",
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "status",
"fieldtype": "Select",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Status",
"length": 0,
"no_copy": 0,
"options": "Connecting to QuickBooks\nConnected to QuickBooks\nIn Progress\nComplete\nFailed",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"collapsible_depends_on": "eval:doc.client_id && doc.client_secret && doc.redirect_url",
"columns": 0,
"fieldname": "application_settings",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Application Settings",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "",
"fieldname": "client_id",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Client ID",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "",
"fieldname": "redirect_url",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Redirect URL",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer",
"fieldname": "token_endpoint",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Token Endpoint",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "application_column_break",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "",
"fieldname": "client_secret",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Client Secret",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "com.intuit.quickbooks.accounting",
"fieldname": "scope",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "Scope",
"length": 0,
"no_copy": 0,
"options": "",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "https://quickbooks.api.intuit.com/v3",
"fieldname": "api_endpoint",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "API Endpoint",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 1,
"columns": 0,
"fieldname": "authorization_settings",
"fieldtype": "Section Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Authorization Settings",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "https://appcenter.intuit.com/connect/oauth2",
"fieldname": "authorization_endpoint",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Authorization Endpoint",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "refresh_token",
"fieldtype": "Small Text",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Refresh Token",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "code",
"fieldtype": "Data",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Code",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "authorization_column_break",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "authorization_url",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Authorization URL",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 1,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "access_token",
"fieldtype": "Small Text",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Access Token",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "quickbooks_company_id",
"fieldtype": "Data",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Quickbooks Company ID",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "company_settings",
"fieldtype": "Section Break",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Company Settings",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "company",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Company",
"length": 0,
"no_copy": 0,
"options": "Company",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "default_shipping_account",
"fieldtype": "Link",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Default Shipping Account",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "default_warehouse",
"fieldtype": "Link",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Default Warehouse",
"length": 0,
"no_copy": 0,
"options": "Warehouse",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "company_column_break",
"fieldtype": "Column Break",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "default_cost_center",
"fieldtype": "Link",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Default Cost Center",
"length": 0,
"no_copy": 0,
"options": "Cost Center",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "undeposited_funds_account",
"fieldtype": "Link",
"hidden": 1,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Undeposited Funds Account",
"length": 0,
"no_copy": 0,
"options": "Account",
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 1,
"istable": 0,
"max_attachments": 0,
"modified": "2018-10-17 03:12:53.506229",
"modified_by": "Administrator",
"module": "ERPNext Integrations",
"name": "QuickBooks Migrator",
"name_case": "",
"owner": "Administrator",
"permissions": [
{
"amend": 0,
"cancel": 0,
"create": 1,
"delete": 1,
"email": 1,
"export": 0,
"if_owner": 0,
"import": 0,
"permlevel": 0,
"print": 1,
"read": 1,
"report": 0,
"role": "System Manager",
"set_user_permissions": 0,
"share": 1,
"submit": 0,
"write": 1
}
],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 1,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 0,
"track_seen": 0,
"track_views": 0
}

File diff suppressed because it is too large Load Diff

View File

@@ -2,15 +2,15 @@
// rename this file from _test_[name] to test_[name] to activate
// and remove above this line
QUnit.test("test: Subscriber", function (assert) {
QUnit.test("test: QuickBooks Migrator", function (assert) {
let done = assert.async();
// number of asserts
assert.expect(1);
frappe.run_serially([
// insert a new Subscriber
() => frappe.tests.make('Subscriber', [
// insert a new QuickBooks Migrator
() => frappe.tests.make('QuickBooks Migrator', [
// values to be set
{key: 'value'}
]),

View File

@@ -3,7 +3,8 @@
# See license.txt
from __future__ import unicode_literals
import frappe
import unittest
class TestSubscriber(unittest.TestCase):
class TestQuickBooksMigrator(unittest.TestCase):
pass

View File

@@ -105,7 +105,9 @@ def get_healthcare_service_unit():
parent_service_unit.healthcare_service_unit_name = "All Healthcare Service Units"
parent_service_unit.is_group = 1
parent_service_unit.save(ignore_permissions = True)
service_unit.parent_healthcare_service_unit = "All Healthcare Service Units"
service_unit.parent_healthcare_service_unit = parent_service_unit.name
else:
service_unit.parent_healthcare_service_unit = service_unit_parent_name[0][0]
service_unit.save(ignore_permissions = True)
return service_unit.name
return service_unit

File diff suppressed because it is too large Load Diff

View File

@@ -339,13 +339,13 @@ def get_events(start, end, filters=None):
data = frappe.db.sql("""select name, patient, practitioner, status,
duration, timestamp(appointment_date, appointment_time) as
'appointment_date' from `tabPatient Appointment` where
'start' from `tabPatient Appointment` where
(appointment_date between %(start)s and %(end)s)
and docstatus < 2 {conditions}""".format(conditions=conditions),
{"start": start, "end": end}, as_dict=True, update={"allDay": 0})
for item in data:
item.appointment_datetime = item.appointment_date + datetime.timedelta(minutes = item.duration)
item.end = item.start + datetime.timedelta(minutes = item.duration)
return data

View File

@@ -10,37 +10,5 @@ frappe.views.calendar["Patient Appointment"] = {
},
order_by: "appointment_date",
gantt: true,
get_events_method: "erpnext.healthcare.doctype.patient_appointment.patient_appointment.get_events",
filters: [
{
'fieldtype': 'Link',
'fieldname': 'practitioner',
'options': 'Healthcare Practitioner',
'label': __('Healthcare Practitioner')
},
{
'fieldtype': 'Link',
'fieldname': 'patient',
'options': 'Patient',
'label': __('Patient')
},
{
'fieldtype': 'Link',
'fieldname': 'appointment_type',
'options': 'Appointment Type',
'label': __('Appointment Type')
},
{
'fieldtype': 'Link',
'fieldname': 'department',
'options': 'Medical Department',
'label': __('Department')
},
{
'fieldtype': 'Select',
'fieldname': 'status',
'options': 'Scheduled\nOpen\nClosed\nPending',
'label': __('Status')
}
]
get_events_method: "erpnext.healthcare.doctype.patient_appointment.patient_appointment.get_events"
};

View File

@@ -342,6 +342,8 @@ def manage_fee_validity(appointment_name, method, ref_invoice=None):
def appointments_valid_in_fee_validity(appointment, invoiced):
valid_days = frappe.db.get_value("Healthcare Settings", None, "valid_days")
max_visit = frappe.db.get_value("Healthcare Settings", None, "max_visit")
if int(max_visit) < 1:
max_visit = 1
valid_days_date = add_days(getdate(appointment.appointment_date), int(valid_days))
return frappe.get_list("Patient Appointment",{'patient': appointment.patient, 'invoiced': invoiced,
'appointment_date':("<=", valid_days_date), 'appointment_date':(">=", getdate(appointment.appointment_date)),

View File

@@ -12,7 +12,7 @@ app_license = "GNU General Public License (v3)"
source_link = "https://github.com/frappe/erpnext"
develop_version = '11.x.x-develop'
staging_version = '11.0.3-beta.5'
staging_version = '11.0.3-beta.14'
error_report_email = "support@erpnext.com"

View File

@@ -9,6 +9,7 @@ from frappe import _
from email_reply_parser import EmailReplyParser
from erpnext.hr.doctype.employee.employee import is_holiday
from frappe.utils import global_date_format
from six import string_types
class DailyWorkSummary(Document):
@@ -108,7 +109,7 @@ def get_user_emails_from_group(group):
:param group: Daily Work Summary Group `name`'''
group_doc = group
if isinstance(group_doc, str):
if isinstance(group_doc, string_types):
group_doc = frappe.get_doc('Daily Work Summary Group', group)
emails = [d.email for d in group_doc.users if frappe.db.get_value("User", d.user, "enabled")]

View File

@@ -2,4 +2,13 @@
// For license information, please see license.txt
frappe.ui.form.on('Driver', {
setup: function(frm) {
frm.set_query('transporter', function(){
return {
filters: {
'is_transporter': 1
}
};
});
}
});

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@
from __future__ import unicode_literals
import frappe
from frappe.utils import getdate, validate_email_add, today, add_years
from frappe.utils import getdate, validate_email_add, today, add_years, format_datetime
from frappe.model.naming import set_name_by_naming_series
from frappe import throw, _, scrub
from frappe.permissions import add_user_permission, remove_user_permission, \
@@ -49,8 +49,7 @@ class Employee(NestedSet):
self.validate_onboarding_process()
if self.user_id:
self.validate_for_enabled_user_id()
self.validate_duplicate_user_id()
self.validate_user_details()
else:
existing_user_id = frappe.db.get_value("Employee", self.name, "user_id")
if existing_user_id:
@@ -60,6 +59,14 @@ class Employee(NestedSet):
def set_employee_name(self):
self.employee_name = ' '.join(filter(lambda x: x, [self.first_name, self.middle_name, self.last_name]))
def validate_user_details(self):
data = frappe.db.get_value('User',
self.user_id, ['enabled', 'user_image'], as_dict=1)
self.image = data.get("user_image")
self.validate_for_enabled_user_id(data.get("enabled", 0))
self.validate_duplicate_user_id()
def update_nsm_model(self):
frappe.utils.nestedset.update_nsm(self)
@@ -143,10 +150,10 @@ class Employee(NestedSet):
if self.status == 'Left' and not self.relieving_date:
throw(_("Please enter relieving date."))
def validate_for_enabled_user_id(self):
def validate_for_enabled_user_id(self, enabled):
if not self.status == 'Active':
return
enabled = frappe.db.get_value("User", self.user_id, "enabled")
if enabled is None:
frappe.throw(_("User {0} does not exist").format(self.user_id))
if enabled == 0:
@@ -223,27 +230,63 @@ def send_birthday_reminders():
if int(frappe.db.get_single_value("HR Settings", "stop_birthday_reminders") or 0):
return
from frappe.utils.user import get_enabled_system_users
users = None
birthdays = get_employees_who_are_born_today()
if birthdays:
if not users:
users = [u.email_id or u.name for u in get_enabled_system_users()]
employee_list = frappe.get_all('Employee',
fields=['name','employee_name'],
filters={'status': 'Active',
'company': birthdays[0]['company']
}
)
employee_emails = get_employee_emails(employee_list)
birthday_names = [name["employee_name"] for name in birthdays]
birthday_emails = [email["user_id"] or email["personal_email"] or email["company_email"] for email in birthdays]
birthdays.append({'company_email': '','employee_name': '','personal_email': '','user_id': ''})
for e in birthdays:
frappe.sendmail(recipients=filter(lambda u: u not in (e.company_email, e.personal_email, e.user_id), users),
subject=_("Birthday Reminder for {0}").format(e.employee_name),
message=_("""Today is {0}'s birthday!""").format(e.employee_name),
reply_to=e.company_email or e.personal_email or e.user_id)
if e['company_email'] or e['personal_email'] or e['user_id']:
if len(birthday_names) == 1:
continue
recipients = e['company_email'] or e['personal_email'] or e['user_id']
else:
recipients = list(set(employee_emails) - set(birthday_emails))
frappe.sendmail(recipients=recipients,
subject=_("Birthday Reminder"),
message=get_birthday_reminder_message(e, birthday_names),
header=['Birthday Reminder', 'green'],
)
def get_birthday_reminder_message(employee, employee_names):
"""Get employee birthday reminder message"""
pattern = "</Li><Br><Li>"
message = pattern.join(filter(lambda u: u not in (employee['employee_name']), employee_names))
message = message.title()
if pattern not in message:
message = "Today is {0}'s birthday \U0001F603".format(message)
else:
message = "Today your colleagues are celebrating their birthdays \U0001F382<br><ul><strong><li> " + message +"</li></strong></ul>"
return message
def get_employees_who_are_born_today():
"""Get Employee properties whose birthday is today."""
return frappe.db.sql("""select name, personal_email, company_email, user_id, employee_name
from tabEmployee where day(date_of_birth) = day(%(date)s)
and month(date_of_birth) = month(%(date)s)
and status = 'Active'""", {"date": today()}, as_dict=True)
return frappe.db.get_values("Employee",
fieldname=["name", "personal_email", "company", "company_email", "user_id", "employee_name"],
filters={
"date_of_birth": ("like", "%{}".format(format_datetime(getdate(), "-MM-dd"))),
"status": "Active",
},
as_dict=True
)
def get_holiday_list_for_employee(employee, raise_exception=True):
if employee:
@@ -319,10 +362,11 @@ def get_employee_emails(employee_list):
for employee in employee_list:
if not employee:
continue
user, email = frappe.db.get_value('Employee', employee, ['user_id', 'company_email'])
if user or email:
employee_emails.append(user or email)
user, company_email, personal_email = frappe.db.get_value('Employee', employee,
['user_id', 'company_email', 'personal_email'])
email = user or company_email or personal_email
if email:
employee_emails.append(email)
return employee_emails
@frappe.whitelist()

View File

@@ -30,8 +30,7 @@ class TestEmployee(unittest.TestCase):
send_birthday_reminders()
email_queue = frappe.db.sql("""select * from `tabEmail Queue`""", as_dict=True)
self.assertTrue("Subject: Birthday Reminder for {0}".format(employee.employee_name) \
in email_queue[0].message)
self.assertTrue("Subject: Birthday Reminder" in email_queue[0].message)
def make_employee(user):
if not frappe.db.get_value("User", user):

View File

@@ -215,10 +215,11 @@ class ExpenseClaim(AccountsController):
self.total_advance_amount += flt(d.allocated_amount)
if self.total_advance_amount:
if flt(self.total_advance_amount) > flt(self.total_claimed_amount):
precision = self.precision("total_advance_amount")
if flt(self.total_advance_amount, precision) > flt(self.total_claimed_amount, precision):
frappe.throw(_("Total advance amount cannot be greater than total claimed amount"))
if self.total_sanctioned_amount \
and flt(self.total_advance_amount) > flt(self.total_sanctioned_amount):
and flt(self.total_advance_amount, precision) > flt(self.total_sanctioned_amount, precision):
frappe.throw(_("Total advance amount cannot be greater than total sanctioned amount"))
def validate_sanctioned_amount(self):

View File

@@ -191,9 +191,8 @@ class LeaveApplication(Document):
frappe.throw(_("The day(s) on which you are applying for leave are holidays. You need not apply for leave."))
if not is_lwp(self.leave_type):
self.leave_balance = get_leave_balance_on(self.employee, self.leave_type, self.from_date,
self.leave_balance = get_leave_balance_on(self.employee, self.leave_type, self.from_date, docname=self.name,
consider_all_leaves_in_the_allocation_period=True)
if self.status != "Rejected" and self.leave_balance < self.total_leave_days:
if frappe.db.get_value("Leave Type", self.leave_type, "allow_negative"):
frappe.msgprint(_("Note: There is not enough leave balance for Leave Type {0}")
@@ -385,26 +384,24 @@ def get_leave_details(employee, date):
return ret
@frappe.whitelist()
def get_leave_balance_on(employee, leave_type, date, allocation_records=None,
def get_leave_balance_on(employee, leave_type, date, allocation_records=None, docname=None,
consider_all_leaves_in_the_allocation_period=False, consider_encashed_leaves=True):
if allocation_records == None:
allocation_records = get_leave_allocation_records(date, employee).get(employee, frappe._dict())
allocation = allocation_records.get(leave_type, frappe._dict())
if consider_all_leaves_in_the_allocation_period:
date = allocation.to_date
leaves_taken = get_leaves_for_period(employee, leave_type, allocation.from_date, date, status="Approved")
leaves_taken = get_leaves_for_period(employee, leave_type, allocation.from_date, date, status="Approved", docname=docname)
leaves_encashed = 0
if frappe.db.get_value("Leave Type", leave_type, 'allow_encashment') and consider_encashed_leaves:
leaves_encashed = flt(allocation.total_leaves_encashed)
return flt(allocation.total_leaves_allocated) - (flt(leaves_taken) + flt(leaves_encashed))
def get_leaves_for_period(employee, leave_type, from_date, to_date, status):
def get_leaves_for_period(employee, leave_type, from_date, to_date, status, docname=None):
leave_applications = frappe.db.sql("""
select employee, leave_type, from_date, to_date, total_leave_days
select name, employee, leave_type, from_date, to_date, total_leave_days
from `tabLeave Application`
where employee=%(employee)s and leave_type=%(leave_type)s
and status = %(status)s and docstatus != 2
@@ -418,9 +415,10 @@ def get_leaves_for_period(employee, leave_type, from_date, to_date, status):
"status": status,
"leave_type": leave_type
}, as_dict=1)
leave_days = 0
for leave_app in leave_applications:
if docname and leave_app.name == docname:
continue
if leave_app.from_date >= getdate(from_date) and leave_app.to_date <= getdate(to_date):
leave_days += leave_app.total_leave_days
else:
@@ -450,7 +448,6 @@ def get_leave_allocation_records(date, employee=None):
"total_leaves_allocated": d.total_leaves_allocated,
"total_leaves_encashed":d.total_leaves_encashed
}))
return allocated_leaves
@frappe.whitelist()

View File

@@ -392,6 +392,34 @@ class TestLeaveApplication(unittest.TestCase):
i += 1
self.assertEqual(get_leave_balance_on(employee.name, leave_type, nowdate()), 6)
# test to not consider current leave in leave balance while submitting
def test_current_leave_on_submit(self):
employee = get_employee()
leave_type = 'Sick leave'
allocation = frappe.get_doc(dict(
doctype = 'Leave Allocation',
employee = employee.name,
leave_type = leave_type,
from_date = '2018-10-01',
to_date = '2018-10-10',
new_leaves_allocated = 1
))
allocation.insert(ignore_permissions=True)
allocation.submit()
leave_application = frappe.get_doc(dict(
doctype = 'Leave Application',
employee = employee.name,
leave_type = leave_type,
from_date = '2018-10-02',
to_date = '2018-10-02',
company = '_Test Company',
status = 'Approved',
leave_approver = 'test@example.com'
))
self.assertTrue(leave_application.insert())
leave_application.submit()
self.assertEqual(leave_application.docstatus, 1)
def make_allocation_record(employee=None, leave_type=None):
frappe.db.sql("delete from `tabLeave Allocation`")

View File

@@ -5,7 +5,7 @@ from __future__ import unicode_literals
import frappe, requests, json, time
from frappe.model.document import Document
from frappe.utils import add_years, now, get_datetime, get_datetime_str
from frappe.utils import add_years, now, get_datetime, get_datetime_str, cint
from frappe import _
from frappe.frappeclient import FrappeClient
from erpnext.utilities.product import get_price, get_qty_in_stock
@@ -84,3 +84,11 @@ class MarketplaceSettings(Document):
def unregister(self):
"""Disable the User on hubmarket.org"""
pass
@frappe.whitelist()
def is_marketplace_enabled():
if not hasattr(frappe.local, 'is_marketplace_enabled'):
frappe.local.is_marketplace_enabled = cint(frappe.db.get_single_value('Marketplace Settings',
'disable_marketplace'))
return frappe.local.is_marketplace_enabled

View File

@@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_events_in_timeline": 0,
"allow_guest_to_view": 0,
"allow_import": 1,
"allow_rename": 0,
@@ -472,6 +473,38 @@
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "allow_same_item_multiple_times",
"fieldtype": "Data",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Allow Same Item Multiple Times",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
@@ -1943,7 +1976,7 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
"modified": "2018-07-15 11:09:19.425998",
"modified": "2018-10-11 11:52:39.047935",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "BOM",

View File

@@ -334,14 +334,15 @@ class BOM(WebsiteGenerator):
frappe.throw(_("Quantity required for Item {0} in row {1}").format(m.item_code, m.idx))
check_list.append(m)
duplicate_items = list(get_duplicates(check_list))
if duplicate_items:
li = []
for i in duplicate_items:
li.append("{0} on row {1}".format(i.item_code, i.idx))
duplicate_list = '<br>' + '<br>'.join(li)
if not self.allow_same_item_multiple_times:
duplicate_items = list(get_duplicates(check_list))
if duplicate_items:
li = []
for i in duplicate_items:
li.append("{0} on row {1}".format(i.item_code, i.idx))
duplicate_list = '<br>' + '<br>'.join(li)
frappe.throw(_("Same item has been entered multiple times. {0}").format(duplicate_list))
frappe.throw(_("Same item has been entered multiple times. {0}").format(duplicate_list))
def check_recursion(self):
""" Check whether recursion occurs in any bom"""
@@ -367,7 +368,8 @@ class BOM(WebsiteGenerator):
bom_list = self.traverse_tree(bom_list)
for bom in bom_list:
bom_obj = frappe.get_doc("BOM", bom)
bom_obj.on_update()
bom_obj.check_recursion()
bom_obj.update_exploded_items()
return bom_list

View File

@@ -62,7 +62,7 @@ class BOMUpdateTool(Document):
bom_list.append(d[0])
self.get_parent_boms(d[0], bom_list)
return bom_list
return list(set(bom_list))
@frappe.whitelist()
def enqueue_replace_bom(args):

View File

@@ -141,9 +141,6 @@ class JobCard(Document):
self.db_set('status', status)
def update_job_card_reference(name, fieldname, value):
frappe.db.set_value('Job Card', name, fieldname, value)
@frappe.whitelist()
def make_material_request(source_name, target_doc=None):
def update_item(obj, target, source_parent):

View File

@@ -0,0 +1,46 @@
// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
/* eslint-disable */
frappe.query_reports["Production Analytics"] = {
"filters": [
{
fieldname: "company",
label: __("Company"),
fieldtype: "Link",
options: "Company",
default: frappe.defaults.get_user_default("Company"),
reqd: 1
},
{
fieldname: "from_date",
label: __("From Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_start_date"),
reqd: 1
},
{
fieldname:"to_date",
label: __("To Date"),
fieldtype: "Date",
default: frappe.defaults.get_user_default("year_end_date"),
reqd: 1
},
{
fieldname: "range",
label: __("Range"),
fieldtype: "Select",
options: [
{ "value": "Weekly", "label": __("Weekly") },
{ "value": "Monthly", "label": __("Monthly") },
{ "value": "Quarterly", "label": __("Quarterly") },
{ "value": "Yearly", "label": __("Yearly") }
],
default: "Monthly",
reqd: 1
}
],
"formatter": function(value, row, column, data) {
return value;
}
}

View File

@@ -0,0 +1,27 @@
{
"add_total_row": 0,
"creation": "2018-10-11 19:28:37.085066",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"idx": 0,
"is_standard": "Yes",
"letter_head": "",
"modified": "2018-10-11 19:28:37.085066",
"modified_by": "Administrator",
"module": "Manufacturing",
"name": "Production Analytics",
"owner": "Administrator",
"prepared_report": 0,
"ref_doctype": "Work Order",
"report_name": "Production Analytics",
"report_type": "Script Report",
"roles": [
{
"role": "Manufacturing User"
},
{
"role": "Stock User"
}
]
}

View File

@@ -0,0 +1,162 @@
# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
from __future__ import unicode_literals
import frappe
from frappe import _
from frappe.utils import getdate
from erpnext.selling.report.sales_analytics.sales_analytics import (get_period_date_ranges,get_period)
def execute(filters=None):
columns = get_columns(filters)
data, chart = get_data(filters,columns)
return columns, data,None ,chart
def get_columns(filters):
columns =[
{
"label": _("Status"),
"fieldname": "Status",
"fieldtype": "Data",
"width": 140
}]
ranges = get_period_date_ranges(period=filters["range"], year_start_date = filters["from_date"],year_end_date=filters["to_date"])
for dummy, end_date in ranges:
label = field_name = get_period(end_date,filters["range"])
columns.append(
{
"label": _(label),
"field_name":field_name,
"fieldtype": "Float",
"width": 120
},
)
return columns
def get_data_list(filters,entry):
data_list = {
"All Work Orders" : {},
"Not Started" : {},
"Overdue" : {},
"Pending" : {},
"Completed" : {}
}
ranges = get_period_date_ranges(period=filters["range"], year_start_date = filters["from_date"],year_end_date=filters["to_date"])
for from_date,end_date in ranges:
period = get_period(end_date,filters["range"])
for d in entry:
if getdate(d.creation) <= getdate(from_date) or getdate(d.creation) <= getdate(end_date) :
data_list = update_data_list(data_list,"All Work Orders",period)
if d.status == 'Completed':
if getdate(d.actual_end_date) < getdate(from_date) or getdate(d.modified) < getdate(from_date):
data_list = update_data_list(data_list, "Completed",period)
elif getdate(d.actual_start_date) < getdate(from_date) :
data_list = update_data_list(data_list, "Pending", period)
elif getdate(d.planned_start_date) < getdate(from_date) :
data_list = update_data_list(data_list, "Overdue", period)
else:
data_list = update_data_list(data_list, "Not Started", period)
elif d.status == 'In Process':
if getdate(d.actual_start_date) < getdate(from_date) :
data_list = update_data_list(data_list, "Pending", period)
elif getdate(d.planned_start_date) < getdate(from_date) :
data_list = update_data_list(data_list, "Overdue", period)
else:
data_list = update_data_list(data_list, "Not Started", period)
elif d.status == 'Not Started':
if getdate(d.planned_start_date) < getdate(from_date) :
data_list = update_data_list(data_list, "Overdue", period)
else:
data_list = update_data_list(data_list, "Not Started", period)
return data_list
def update_data_list(data_list, status, period):
if data_list.get(status).get(period):
data_list[status][period] += 1
else:
data_list[status][period] = 1
return data_list
def get_data(filters,columns):
data = []
entry = frappe.get_all("Work Order",
fields=["creation", "modified", "actual_start_date", "actual_end_date", "planned_start_date", "planned_end_date", "status"],
filters={"docstatus" : 1, "company" : filters["company"] })
data_list = get_data_list(filters,entry)
labels = ["All Work Orders", "Not Started", "Overdue", "Pending", "Completed"]
chart_data = get_chart_data(data_list,columns)
ranges = get_period_date_ranges(period=filters["range"], year_start_date = filters["from_date"],year_end_date=filters["to_date"])
for label in labels:
work = {}
work["Status"] = label
for dummy,end_date in ranges:
period = get_period(end_date,filters["range"])
if data_list.get(label).get(period):
work[period] = data_list.get(label).get(period)
else:
work[period] = 0.0
data.append(work)
return data, chart_data
def get_chart_data(data_list,columns):
labels = [d.get("label") for d in columns[1:]]
all_data, not_start, overdue, pending, completed = [], [], [] , [], []
datasets = []
for d in labels:
all_data.append(data_list.get("All Work Orders").get(d))
not_start.append(data_list.get("Not Started").get(d))
overdue.append(data_list.get("Overdue").get(d))
pending.append(data_list.get("Pending").get(d))
completed.append(data_list.get("Completed").get(d))
datasets.append({'name':'All Work Orders', 'values': all_data})
datasets.append({'name':'Not Started', 'values': not_start})
datasets.append({'name':'Overdue', 'values': overdue})
datasets.append({'name':'Pending', 'values': pending})
datasets.append({'name':'Completed', 'values': completed})
chart = {
"data": {
'labels': labels,
'datasets':datasets
}
}
chart["type"] = "line"
return chart

View File

@@ -498,7 +498,6 @@ execute:frappe.delete_doc('DocType', 'Production Planning Tool', ignore_missing=
erpnext.patches.v10_0.migrate_daily_work_summary_settings_to_daily_work_summary_group
erpnext.patches.v10_0.add_default_cash_flow_mappers
erpnext.patches.v11_0.make_quality_inspection_template
erpnext.patches.v10_0.remove_and_copy_fields_in_physician
erpnext.patches.v10_0.update_status_for_multiple_source_in_po
erpnext.patches.v10_0.set_auto_created_serial_no_in_stock_entry
erpnext.patches.v10_0.update_territory_and_customer_group
@@ -569,3 +568,7 @@ erpnext.patches.v11_0.remove_land_unit_icon
erpnext.patches.v11_0.add_default_dispatch_notification_template
erpnext.patches.v11_0.add_market_segments
erpnext.patches.v11_0.add_sales_stages
erpnext.patches.v11_0.ewaybill_fields_gst_india
erpnext.patches.v11_0.drop_column_max_days_allowed
erpnext.patches.v11_0.change_healthcare_desktop_icons
erpnext.patches.v10_0.update_user_image_in_employee

View File

@@ -1,13 +0,0 @@
import frappe
def execute():
if frappe.db.exists("DocType", "Physician"):
frappe.reload_doc("healthcare", "doctype", "physician")
frappe.reload_doc("healthcare", "doctype", "physician_service_unit_schedule")
if frappe.db.has_column('Physician', 'physician_schedules'):
for doc in frappe.get_all('Physician'):
_doc = frappe.get_doc('Physician', doc.name)
if _doc.physician_schedule:
_doc.append('physician_schedules', {'schedule': _doc.physician_schedule})
_doc.save()

View File

@@ -0,0 +1,19 @@
# Copyright (c) 2017, Frappe and Contributors
# License: GNU General Public License v3. See license.txt
from __future__ import unicode_literals
import frappe
def execute():
frappe.reload_doc('hr', 'doctype', 'employee')
frappe.db.sql("""
UPDATE
`tabEmployee`, `tabUser`
SET
`tabEmployee`.image = `tabUser`.user_image
WHERE
`tabEmployee`.user_id = `tabUser`.name and
`tabEmployee`.user_id is not null and
`tabEmployee`.user_id != '' and `tabEmployee`.image is null
""")

View File

@@ -0,0 +1,93 @@
import frappe
from frappe import _
change_icons_map = [
{
"module_name": "Patient",
"color": "#6BE273",
"icon": "fa fa-user",
"doctype": "Patient",
"type": "link",
"link": "List/Patient",
"label": _("Patient")
},
{
"module_name": "Patient Encounter",
"color": "#2ecc71",
"icon": "fa fa-stethoscope",
"doctype": "Patient Encounter",
"type": "link",
"link": "List/Patient Encounter",
"label": _("Patient Encounter"),
},
{
"module_name": "Healthcare Practitioner",
"color": "#2ecc71",
"icon": "fa fa-user-md",
"doctype": "Healthcare Practitioner",
"type": "link",
"link": "List/Healthcare Practitioner",
"label": _("Healthcare Practitioner")
},
{
"module_name": "Patient Appointment",
"color": "#934F92",
"icon": "fa fa-calendar-plus-o",
"doctype": "Patient Appointment",
"type": "link",
"link": "List/Patient Appointment",
"label": _("Patient Appointment")
},
{
"module_name": "Lab Test",
"color": "#7578f6",
"icon": "octicon octicon-beaker",
"doctype": "Lab Test",
"type": "link",
"link": "List/Lab Test",
"label": _("Lab Test")
}
]
def execute():
change_healthcare_desktop_icons()
def change_healthcare_desktop_icons():
doctypes = ["patient", "patient_encounter", "healthcare_practitioner",
"patient_appointment", "lab_test"]
for doctype in doctypes:
frappe.reload_doc("healthcare", "doctype", doctype)
for spec in change_icons_map:
frappe.db.sql("""
delete from `tabDesktop Icon`
where _doctype = '{0}'
""".format(spec['doctype']))
desktop_icon = frappe.new_doc("Desktop Icon")
desktop_icon.hidden = 1
desktop_icon.standard = 1
desktop_icon.icon = spec['icon']
desktop_icon.color = spec['color']
desktop_icon.module_name = spec['module_name']
desktop_icon.label = spec['label']
desktop_icon.app = "erpnext"
desktop_icon.type = spec['type']
desktop_icon._doctype = spec['doctype']
desktop_icon.link = spec['link']
desktop_icon.save(ignore_permissions=True)
frappe.db.sql("""
delete from `tabDesktop Icon`
where module_name = 'Healthcare' and type = 'module'
""")
desktop_icon = frappe.new_doc("Desktop Icon")
desktop_icon.hidden = 1
desktop_icon.standard = 1
desktop_icon.icon = "fa fa-heartbeat"
desktop_icon.color = "#FF888B"
desktop_icon.module_name = "Healthcare"
desktop_icon.label = _("Healthcare")
desktop_icon.app = "erpnext"
desktop_icon.type = 'module'
desktop_icon.save(ignore_permissions=True)

View File

@@ -0,0 +1,6 @@
import frappe
def execute():
if frappe.db.exists("DocType", "Leave Type"):
if 'max_days_allowed' in frappe.db.get_table_columns("Leave Type"):
frappe.db.sql("alter table `tabLeave Type` drop column max_days_allowed")

View File

@@ -0,0 +1,9 @@
import frappe
from erpnext.regional.india.setup import make_custom_fields
def execute():
company = frappe.get_all('Company', filters = {'country': 'India'})
if not company:
return
make_custom_fields()

View File

@@ -6,6 +6,7 @@ import frappe
from frappe.utils.nestedset import rebuild_tree
def execute():
if not frappe.db.get_value('Asset', {'docstatus': ('<', 2) }, 'name'): return
frappe.reload_doc('assets', 'doctype', 'location')
frappe.reload_doc('stock', 'doctype', 'warehouse')

View File

@@ -106,6 +106,8 @@ def get_series():
continue
if not frappe.db.has_column(doctype, 'naming_series'):
continue
if not frappe.get_meta(doctype).has_field('naming_series'):
continue
series_to_preserve = list(filter(None, get_series_to_preserve(doctype)))
default_series = get_default_series(doctype)
@@ -128,5 +130,6 @@ def get_series_to_preserve(doctype):
return series_to_preserve
def get_default_series(doctype):
default_series = (frappe.get_meta(doctype).get_field("naming_series").default or "")
field = frappe.get_meta(doctype).get_field("naming_series")
default_series = field.get('default', '') if field else ''
return default_series

View File

@@ -0,0 +1,15 @@
import frappe
from frappe.model.utils.rename_field import rename_field
def execute():
""" copy subscribe field to customer """
frappe.reload_doc("accounts","doctype","subscription")
if frappe.db.exists("DocType", "Subscriber"):
if frappe.db.has_column('Subscription','subscriber'):
frappe.db.sql("""
update `tabSubscription` s1
set customer=(select customer from tabSubscriber where name=s1.subscriber)
""")
frappe.delete_doc("DocType", "Subscriber")

View File

@@ -54,3 +54,13 @@ def execute():
update `tabPractitioner Service Unit Schedule` set parentfield = 'practitioner_schedules'
where parentfield = 'physician_schedules' and parenttype = 'Healthcare Practitioner'
""")
if frappe.db.exists("DocType", "Healthcare Practitioner"):
frappe.reload_doc("healthcare", "doctype", "healthcare_practitioner")
frappe.reload_doc("healthcare", "doctype", "practitioner_service_unit_schedule")
if frappe.db.has_column('Healthcare Practitioner', 'physician_schedule'):
for doc in frappe.get_all('Healthcare Practitioner'):
_doc = frappe.get_doc('Healthcare Practitioner', doc.name)
if _doc.physician_schedule:
_doc.append('practitioner_schedules', {'schedule': _doc.physician_schedule})
_doc.save()

View File

@@ -187,6 +187,7 @@ class Project(Document):
frappe.db.set_value("Sales Order", self.sales_order, "project", self.name)
def update_percent_complete(self):
if not self.tasks: return
total = frappe.db.sql("""select count(name) from tabTask where project=%s""", self.name)[0][0]
if not total and self.percent_complete:
self.percent_complete = 0

View File

@@ -1,5 +1,6 @@
{
"allow_copy": 0,
"allow_guest_to_view": 0,
"allow_import": 0,
"allow_rename": 0,
"beta": 0,
@@ -11,16 +12,21 @@
"editable_grid": 1,
"fields": [
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "user",
"fieldtype": "Link",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "User",
"length": 0,
"no_copy": 0,
@@ -30,23 +36,30 @@
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 1,
"search_index": 1,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"fieldname": "welcome_email_sent",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 0,
"in_standard_filter": 0,
"label": "Welcome email sent",
"length": 0,
"no_copy": 0,
@@ -55,24 +68,58 @@
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
},
{
"allow_bulk_edit": 0,
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 1,
"fieldname": "view_attachments",
"fieldtype": "Check",
"hidden": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_standard_filter": 0,
"label": "View attachments",
"length": 0,
"no_copy": 0,
"permlevel": 0,
"precision": "",
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"remember_last_selected_value": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"set_only_once": 0,
"translatable": 0,
"unique": 0
}
],
"has_web_view": 0,
"hide_heading": 0,
"hide_toolbar": 0,
"idx": 0,
"image_view": 0,
"in_create": 0,
"is_submittable": 0,
"issingle": 0,
"istable": 1,
"max_attachments": 0,
"modified": "2016-07-11 03:28:04.756894",
"modified": "2018-09-09 12:39:38.376816",
"modified_by": "Administrator",
"module": "Projects",
"name": "Project User",
@@ -82,7 +129,10 @@
"quick_entry": 0,
"read_only": 0,
"read_only_onload": 0,
"show_name_in_global_search": 0,
"sort_field": "modified",
"sort_order": "DESC",
"track_seen": 0
"track_changes": 0,
"track_seen": 0,
"track_views": 0
}

View File

@@ -235,6 +235,69 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
this.get_terms();
},
link_to_mrs: function() {
var my_items = [];
for (var i in cur_frm.doc.items) {
if(!cur_frm.doc.items[i].material_request){
my_items.push(cur_frm.doc.items[i].item_code);
}
}
frappe.call({
method: "erpnext.buying.utils.get_linked_material_requests",
args:{
items: my_items
},
callback: function(r) {
if(!r.message) {
frappe.throw(__("No pending Material Requests found to link for the given items."))
}
else {
var i = 0;
var item_length = cur_frm.doc.items.length;
while (i < item_length) {
var qty = cur_frm.doc.items[i].qty;
(r.message[0] || []).forEach(function(d) {
if (d.qty > 0 && qty > 0 && cur_frm.doc.items[i].item_code == d.item_code && !cur_frm.doc.items[i].material_request_item)
{
cur_frm.doc.items[i].material_request = d.mr_name;
cur_frm.doc.items[i].material_request_item = d.mr_item;
var my_qty = Math.min(qty, d.qty);
qty = qty - my_qty;
d.qty = d.qty - my_qty;
cur_frm.doc.items[i].stock_qty = my_qty*cur_frm.doc.items[i].conversion_factor;
cur_frm.doc.items[i].qty = my_qty;
frappe.msgprint("Assigning " + d.mr_name + " to " + d.item_code + " (row " + cur_frm.doc.items[i].idx + ")");
if (qty > 0)
{
frappe.msgprint("Splitting " + qty + " units of " + d.item_code);
var newrow = frappe.model.add_child(cur_frm.doc, cur_frm.doc.items[i].doctype, "items");
item_length++;
for (var key in cur_frm.doc.items[i])
{
newrow[key] = cur_frm.doc.items[i][key];
}
newrow.idx = item_length;
newrow["stock_qty"] = newrow.conversion_factor*qty;
newrow["qty"] = qty;
newrow["material_request"] = "";
newrow["material_request_item"] = "";
}
}
});
i++;
}
refresh_field("items");
//cur_frm.save();
}
}
});
},
update_auto_repeat_reference: function(doc) {
if (doc.auto_repeat) {
frappe.call({

View File

@@ -161,7 +161,7 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
if(cumulated_tax_fraction && !me.discount_amount_applied) {
item.net_amount = flt(item.amount / (1 + cumulated_tax_fraction));
item.net_rate = flt(item.net_amount / item.qty, precision("net_rate", item));
item.net_rate = item.qty ? flt(item.net_amount / item.qty, precision("net_rate", item)) : 0;
me.set_in_company_currency(item, ["net_rate", "net_amount"]);
}
@@ -521,7 +521,7 @@ erpnext.taxes_and_totals = erpnext.payments.extend({
item.net_amount = flt(item.net_amount + discount_amount_loss,
precision("net_amount", item));
}
item.net_rate = flt(item.net_amount / item.qty, precision("net_rate", item));
item.net_rate = item.qty ? flt(item.net_amount / item.qty, precision("net_rate", item)) : 0;
me.set_in_company_currency(item, ["net_rate", "net_amount"]);
});

View File

@@ -286,6 +286,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
me.frm.set_value("taxes", r.message.taxes);
}
},
() => me.set_dynamic_labels(),
() => me.calculate_taxes_and_totals()
]);
}
@@ -845,16 +846,10 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
this.frm.toggle_reqd("plc_conversion_rate",
!!(this.frm.doc.price_list_name && this.frm.doc.price_list_currency));
if(this.frm.doc_currency!==this.frm.doc.currency
|| this.frm.doc_currency!==this.frm.doc.price_list_currency) {
// reset names only when the currency is different
var company_currency = this.get_company_currency();
this.change_form_labels(company_currency);
this.change_grid_labels(company_currency);
this.frm.refresh_fields();
this.frm.doc_currency = this.frm.doc.currency;
}
var company_currency = this.get_company_currency();
this.change_form_labels(company_currency);
this.change_grid_labels(company_currency);
this.frm.refresh_fields();
},
change_form_labels: function(company_currency) {

View File

@@ -32,8 +32,9 @@ frappe.views.marketplaceFactory = class marketplaceFactory extends frappe.views.
};
function is_marketplace_disabled() {
return frappe.model.with_doc('Marketplace Settings')
.then(doc => doc.disable_marketplace);
return frappe.call({
method: "erpnext.hub_node.doctype.marketplace_settings.marketplace_settings.is_marketplace_enabled"
}).then(r => r.message)
}
$(document).on('toolbar_setup', () => {

View File

@@ -82,7 +82,7 @@
{% for(var j=i*3; j
<(i+1)*3; j++) { %} <button type="button" class="btn btn-default numeric-keypad" val="{{j+1}}">{{j+1}}</button>
{% } %}
<button type="button" {% if((!allow_user_to_edit_rate && chartData[i] == __("Price")) || (!allow_user_to_edit_discount && chartData[i] == __("Disc"))) { %} disabled {% } %} id="pos-item-{{ chartData[i].toLowerCase() }}" class="btn text-center btn-default numeric-keypad pos-operation">{{ __(chartData[i]) }}</button>
<button type="button" {% if((!allow_user_to_edit_rate && __(chartData[i]) == __("Price")) || (!allow_user_to_edit_discount && __(chartData[i]) == __("Disc"))) { %} disabled {% } %} id="pos-item-{{ chartData[i].toLowerCase() }}" class="btn text-center btn-default numeric-keypad pos-operation">{{ __(chartData[i]) }}</button>
</div>
{% } %}
<div class="row text-right">

View File

@@ -164,6 +164,43 @@ def make_custom_fields(update=True):
fieldtype='Check', insert_after='disabled', print_hide=1)
]
ewaybill_fields = [
{
'fieldname': 'distance',
'label': 'Distance (in km)',
'fieldtype': 'Float',
'insert_after': 'vehicle_no',
'print_hide': 1
},
{
'fieldname': 'gst_transporter_id',
'label': 'GST Transporter ID',
'fieldtype': 'Data',
'insert_after': 'transporter_name',
'fetch_from': 'transporter.gst_transporter_id',
'print_hide': 1
},
{
'fieldname': 'mode_of_transport',
'label': 'Mode of Transport',
'fieldtype': 'Select',
'options': '\nRoad\nAir\nRail\nShip',
'default': 'Road',
'insert_after': 'lr_date',
'print_hide': 1
},
{
'fieldname': 'gst_vehicle_type',
'label': 'GST Vehicle Type',
'fieldtype': 'Select',
'options': '\nRegular\nOver Dimensional Cargo (ODC)',
'default': 'Regular',
'depends_on': 'eval:(doc.mode_of_transport === "Road")',
'insert_after': 'mode_of_transport',
'print_hide': 1
}
]
custom_fields = {
'Address': [
dict(fieldname='gstin', label='Party GSTIN', fieldtype='Data',
@@ -175,7 +212,7 @@ def make_custom_fields(update=True):
],
'Purchase Invoice': invoice_gst_fields + purchase_invoice_gst_fields,
'Sales Invoice': invoice_gst_fields + sales_invoice_gst_fields,
'Delivery Note': sales_invoice_gst_fields,
'Delivery Note': sales_invoice_gst_fields + ewaybill_fields,
'Sales Taxes and Charges Template': inter_state_gst_field,
'Purchase Taxes and Charges Template': inter_state_gst_field,
'Item': [
@@ -240,6 +277,15 @@ def make_custom_fields(update=True):
fieldtype='Currency', insert_after='monthly_house_rent', read_only=1),
dict(fieldname='total_eligible_hra_exemption', label='Total Eligible HRA Exemption',
fieldtype='Currency', insert_after='monthly_hra_exemption', read_only=1)
],
'Supplier': [
{
'fieldname': 'gst_transporter_id',
'label': 'GST Transporter ID',
'fieldtype': 'Data',
'insert_after': 'supplier_type',
'depends_on': 'eval:doc.is_transporter'
}
]
}

View File

@@ -82,7 +82,7 @@ def get_place_of_supply(out, doctype):
if address_name:
address = frappe.db.get_value("Address", address_name, ["gst_state", "gst_state_number"], as_dict=1)
if address.gst_state and address.gst_state_number:
if address and address.gst_state and address.gst_state_number:
return cstr(address.gst_state_number) + "-" + cstr(address.gst_state)
def get_regional_address_details(out, doctype, company):

View File

@@ -21,7 +21,7 @@ def get_data(filters):
data = frappe.db.sql("""
SELECT
dn.name as dn_id, dn.posting_date, dn.company, dn.company_gstin, dn.customer, dn.customer_gstin, dni.item_code, dni.item_name, dni.description, dni.gst_hsn_code, dni.uom, dni.qty, dni.amount, dn.transport_mode, dn.distance, dn.transporter_name, dn.transporter, dn.lr_no, dn.lr_date, dn.vehicle_no, dn.vehicle_type, dn.company_address, dn.shipping_address_name
dn.name as dn_id, dn.posting_date, dn.company, dn.company_gstin, dn.customer, dn.customer_gstin, dni.item_code, dni.item_name, dni.description, dni.gst_hsn_code, dni.uom, dni.qty, dni.amount, dn.mode_of_transport, dn.distance, dn.transporter_name, dn.gst_transporter_id, dn.lr_no, dn.lr_date, dn.vehicle_no, dn.gst_vehicle_type, dn.company_address, dn.shipping_address_name
FROM
`tabDelivery Note` AS dn join `tabDelivery Note Item` AS dni on (dni.parent = dn.name)
WHERE
@@ -52,6 +52,9 @@ def get_data(filters):
row.posting_date = '/'.join(str(row.posting_date).replace("-", "/").split('/')[::-1])
row.lr_date = '/'.join(str(row.lr_date).replace("-", "/").split('/')[::-1])
if row.gst_vehicle_type == 'Over Dimensional Cargo (ODC)':
row.gst_vehicle_type = 'ODC'
row.item_name = re.sub(special_characters, " ", row.item_name)
row.description = row.item_name
@@ -333,8 +336,8 @@ def get_columns():
"width": 100
},
{
"fieldname": "transport_mode",
"label": _("Transport Mode"),
"fieldname": "mode_of_transport",
"label": _("Mode of Transport"),
"fieldtype": "Data",
"width": 100
},
@@ -351,20 +354,20 @@ def get_columns():
"width": 120
},
{
"fieldname": "transporter_id",
"fieldname": "gst_transporter_id",
"label": _("Transporter ID"),
"fieldtype": "Data",
"width": 100
},
{
"fieldname": "lr_no",
"label": _("Transporter Doc No"),
"label": _("Transport Receipt No"),
"fieldtype": "Data",
"width": 120
},
{
"fieldname": "lr_date",
"label": _("Transporter Date"),
"label": _("Transport Receipt Date"),
"fieldtype": "Data",
"width": 120
},
@@ -375,7 +378,7 @@ def get_columns():
"width": 100
},
{
"fieldname": "vehicle_type",
"fieldname": "gst_vehicle_type",
"label": _("Vehicle Type"),
"fieldtype": "Data",
"width": 100

View File

@@ -105,9 +105,12 @@ def get_result_as_list(data, filters):
for d in data:
JournalCode = re.split("-|/", d.get("voucher_no"))[0]
JournalCode = re.split("-|/|[0-9]", d.get("voucher_no"))[0]
EcritureNum = re.split("-|/", d.get("voucher_no"))[1]
if d.get("voucher_no").startswith("{0}-".format(JournalCode)) or d.get("voucher_no").startswith("{0}/".format(JournalCode)):
EcritureNum = re.split("-|/", d.get("voucher_no"))[1]
else:
EcritureNum = re.search("{0}(\d+)".format(JournalCode), d.get("voucher_no"), re.IGNORECASE).group(1)
EcritureDate = format_datetime(d.get("GlPostDate"), "yyyyMMdd")

View File

@@ -7,15 +7,15 @@ from erpnext.accounts.report.item_wise_purchase_register.item_wise_purchase_regi
def execute(filters=None):
return _execute(filters, additional_table_columns=[
dict(fieldtype='Data', label='Supplier GSTIN', width=120),
dict(fieldtype='Data', label='Company GSTIN', width=120),
dict(fieldtype='Data', label='Reverse Charge', width=120),
dict(fieldtype='Data', label='Invoice Type', width=120),
dict(fieldtype='Data', label='Export Type', width=120),
dict(fieldtype='Data', label='E-Commerce GSTIN', width=130),
dict(fieldtype='Data', label='HSN Code', width=120),
dict(fieldtype='Data', label='Supplier Invoice No', width=120),
dict(fieldtype='Date', label='Supplier Invoice Date', width=100)
dict(fieldtype='Data', label='Supplier GSTIN', fieldname="supplier_gstin", width=120),
dict(fieldtype='Data', label='Company GSTIN', fieldname="company_gstin", width=120),
dict(fieldtype='Data', label='Reverse Charge', fieldname="reverse_charge", width=120),
dict(fieldtype='Data', label='Invoice Type', fieldname="invoice_type", width=120),
dict(fieldtype='Data', label='Export Type', fieldname="export_type", width=120),
dict(fieldtype='Data', label='E-Commerce GSTIN', fieldname="ecommerce_gstin", width=130),
dict(fieldtype='Data', label='HSN Code', fieldname="hsn_code", width=120),
dict(fieldtype='Data', label='Supplier Invoice No', fieldname="supplier_invoice_no", width=120),
dict(fieldtype='Date', label='Supplier Invoice Date', fieldname="supplier_invoice_date", width=100)
], additional_query_columns=[
'supplier_gstin',
'company_gstin',

View File

@@ -7,15 +7,15 @@ from erpnext.accounts.report.item_wise_sales_register.item_wise_sales_register i
def execute(filters=None):
return _execute(filters, additional_table_columns=[
dict(fieldtype='Data', label='Customer GSTIN', width=120),
dict(fieldtype='Data', label='Billing Address GSTIN', width=140),
dict(fieldtype='Data', label='Company GSTIN', width=120),
dict(fieldtype='Data', label='Place of Supply', width=120),
dict(fieldtype='Data', label='Reverse Charge', width=120),
dict(fieldtype='Data', label='Invoice Type', width=120),
dict(fieldtype='Data', label='Export Type', width=120),
dict(fieldtype='Data', label='E-Commerce GSTIN', width=130),
dict(fieldtype='Data', label='HSN Code', width=120)
dict(fieldtype='Data', label='Customer GSTIN', fieldname="customer_gstin", width=120),
dict(fieldtype='Data', label='Billing Address GSTIN', fieldname="billing_address_gstin", width=140),
dict(fieldtype='Data', label='Company GSTIN', fieldname="company_gstin", width=120),
dict(fieldtype='Data', label='Place of Supply', fieldname="place_of_supply", width=120),
dict(fieldtype='Data', label='Reverse Charge', fieldname="reverse_charge", width=120),
dict(fieldtype='Data', label='Invoice Type', fieldname="invoice_type", width=120),
dict(fieldtype='Data', label='Export Type', fieldname="export_type", width=120),
dict(fieldtype='Data', label='E-Commerce GSTIN', fieldname="ecommerce_gstin", width=130),
dict(fieldtype='Data', label='HSN Code', fieldname="hsn_code", width=120)
], additional_query_columns=[
'customer_gstin',
'billing_address_gstin',

View File

@@ -7,12 +7,12 @@ from erpnext.accounts.report.purchase_register.purchase_register import _execute
def execute(filters=None):
return _execute(filters, additional_table_columns=[
dict(fieldtype='Data', label='Supplier GSTIN', width=120),
dict(fieldtype='Data', label='Company GSTIN', width=120),
dict(fieldtype='Data', label='Reverse Charge', width=120),
dict(fieldtype='Data', label='Invoice Type', width=120),
dict(fieldtype='Data', label='Export Type', width=120),
dict(fieldtype='Data', label='E-Commerce GSTIN', width=130)
dict(fieldtype='Data', label='Supplier GSTIN', fieldname="supplier_gstin", width=120),
dict(fieldtype='Data', label='Company GSTIN', fieldname="company_gstin", width=120),
dict(fieldtype='Data', label='Reverse Charge', fieldname="reverse_charge", width=120),
dict(fieldtype='Data', label='Invoice Type', fieldname="invoice_type", width=120),
dict(fieldtype='Data', label='Export Type', fieldname="export_type", width=120),
dict(fieldtype='Data', label='E-Commerce GSTIN', fieldname="ecommerce_gstin", width=130)
], additional_query_columns=[
'supplier_gstin',
'company_gstin',

View File

@@ -7,14 +7,14 @@ from erpnext.accounts.report.sales_register.sales_register import _execute
def execute(filters=None):
return _execute(filters, additional_table_columns=[
dict(fieldtype='Data', label='Customer GSTIN', width=120),
dict(fieldtype='Data', label='Billing Address GSTIN', width=140),
dict(fieldtype='Data', label='Company GSTIN', width=120),
dict(fieldtype='Data', label='Place of Supply', width=120),
dict(fieldtype='Data', label='Reverse Charge', width=120),
dict(fieldtype='Data', label='Invoice Type', width=120),
dict(fieldtype='Data', label='Export Type', width=120),
dict(fieldtype='Data', label='E-Commerce GSTIN', width=130)
dict(fieldtype='Data', label='Customer GSTIN', fieldname="customer_gstin", width=120),
dict(fieldtype='Data', label='Billing Address GSTIN', fieldname="billing_address_gstin", width=140),
dict(fieldtype='Data', label='Company GSTIN', fieldname="company_gstin", width=120),
dict(fieldtype='Data', label='Place of Supply', fieldname="place_of_supply", width=120),
dict(fieldtype='Data', label='Reverse Charge', fieldname="reverse_charge", width=120),
dict(fieldtype='Data', label='Invoice Type', fieldname="invoice_type", width=120),
dict(fieldtype='Data', label='Export Type', fieldname="export_type", width=120),
dict(fieldtype='Data', label='E-Commerce GSTIN', fieldname="ecommerce_gstin", width=130)
], additional_query_columns=[
'customer_gstin',
'billing_address_gstin',

View File

@@ -25,6 +25,10 @@ def get_data():
{
'label': _('Pricing'),
'items': ['Pricing Rule']
},
{
'label': _('Subscriptions'),
'items': ['Subscription']
}
]
}

Some files were not shown because too many files have changed in this diff Show More