stockor 0.1.9 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/Gemfile.lock +254 -72
- data/Guardfile +1 -1
- data/README.md +24 -3
- data/app.json +28 -0
- data/client/skr/Extension.coffee +18 -0
- data/client/skr/components/BankAccountFinder.cjsx +34 -0
- data/client/skr/components/Currency.cjsx +19 -0
- data/client/skr/components/CustomerFinder.cjsx +37 -0
- data/client/skr/components/CustomerLink.cjsx +13 -0
- data/client/skr/components/CustomerProjectFinder.cjsx +49 -0
- data/client/skr/components/GlAccountChooser.cjsx +38 -0
- data/client/skr/components/InvoiceFinder.cjsx +37 -0
- data/client/skr/components/InvoiceLink.cjsx +13 -0
- data/client/skr/components/LocationChooser.cjsx +37 -0
- data/client/skr/components/PaymentCategoryFinder.cjsx +34 -0
- data/client/skr/components/PrintFormChooser.cjsx +29 -0
- data/client/skr/components/SalesOrderFinder.cjsx +38 -0
- data/client/skr/components/ScreenControls.cjsx +20 -0
- data/client/skr/components/SkuFinder.cjsx +30 -0
- data/client/skr/components/SkuLines.cjsx +76 -0
- data/client/skr/components/SystemSettings.cjsx +26 -0
- data/client/skr/components/TermsChooser.cjsx +40 -0
- data/client/skr/components/ToolbarButton.cjsx +7 -0
- data/client/skr/components/TotalsLine.cjsx +21 -0
- data/client/skr/components/TriStateIcon.cjsx +12 -0
- data/client/skr/components/UOMChooser.cjsx +24 -0
- data/client/skr/components/UserPreferences.cjsx +30 -0
- data/client/skr/components/VendorFinder.cjsx +40 -0
- data/client/skr/components/address/Address.cjsx +10 -10
- data/client/skr/components/styles.scss +16 -0
- data/client/skr/index.js +3 -1
- data/client/skr/models/Address.coffee +9 -1
- data/client/skr/models/BankAccount.coffee +17 -0
- data/client/skr/models/Base.coffee +6 -0
- data/client/skr/models/Customer.coffee +17 -10
- data/client/skr/models/CustomerProject.coffee +29 -0
- data/client/skr/models/GlAccount.coffee +22 -10
- data/client/skr/models/GlManualEntry.coffee +4 -2
- data/client/skr/models/GlPeriod.coffee +4 -6
- data/client/skr/models/GlPosting.coffee +7 -7
- data/client/skr/models/GlTransaction.coffee +3 -3
- data/client/skr/models/IaLine.coffee +9 -9
- data/client/skr/models/IaReason.coffee +4 -4
- data/client/skr/models/InvLine.coffee +30 -11
- data/client/skr/models/InventoryAdjustment.coffee +8 -6
- data/client/skr/models/Invoice.coffee +89 -18
- data/client/skr/models/Location.coffee +27 -6
- data/client/skr/models/Payment.coffee +36 -0
- data/client/skr/models/PaymentCategory.coffee +12 -0
- data/client/skr/models/PaymentTerm.coffee +17 -4
- data/client/skr/models/PickTicket.coffee +7 -5
- data/client/skr/models/PoLine.coffee +15 -15
- data/client/skr/models/PoReceipt.coffee +8 -6
- data/client/skr/models/PorLine.coffee +11 -11
- data/client/skr/models/PricingProvider.coffee +6 -0
- data/client/skr/models/PtLine.coffee +13 -13
- data/client/skr/models/PurchaseOrder.coffee +11 -9
- data/client/skr/models/SalesOrder.coffee +59 -22
- data/client/skr/models/Sku.coffee +17 -15
- data/client/skr/models/SkuLoc.coffee +14 -9
- data/client/skr/models/SkuTran.coffee +10 -10
- data/client/skr/models/SkuVendor.coffee +9 -9
- data/client/skr/models/SoLine.coffee +27 -20
- data/client/skr/models/TimeEntry.coffee +75 -0
- data/client/skr/models/Uom.coffee +27 -6
- data/client/skr/models/Vendor.coffee +14 -12
- data/client/skr/models/VoLine.coffee +11 -11
- data/client/skr/models/Voucher.coffee +7 -5
- data/client/skr/models/mixins/HasVisibleId.coffee +7 -0
- data/client/skr/models/mixins/PrintSupport.coffee +6 -0
- data/client/skr/models/mixins/SkuLine.coffee +61 -0
- data/client/skr/screens/Commands.coffee +29 -0
- data/client/skr/screens/bank-maint/BankMaint.cjsx +43 -0
- data/client/skr/screens/bank-maint/index.js +5 -0
- data/client/skr/screens/chart-of-accounts/ChartOfAccounts.cjsx +40 -0
- data/client/skr/screens/chart-of-accounts/index.js +1 -0
- data/client/skr/screens/chart-of-accounts/index.scss +12 -0
- data/client/skr/screens/customer-maint/CustomerMaint.cjsx +35 -36
- data/client/skr/screens/customer-projects/CustomerProjects.cjsx +70 -0
- data/client/skr/screens/customer-projects/index.js +5 -0
- data/client/skr/screens/customer-projects/index.scss +25 -0
- data/client/skr/screens/fresh-books-import/ApiInfo.cjsx +35 -0
- data/client/skr/screens/fresh-books-import/ChooseRecords.cjsx +116 -0
- data/client/skr/screens/fresh-books-import/FreshBooksImport.cjsx +31 -0
- data/client/skr/screens/fresh-books-import/Import.coffee +52 -0
- data/client/skr/screens/fresh-books-import/ViewRecords.cjsx +96 -0
- data/client/skr/screens/fresh-books-import/index.js +1 -0
- data/client/skr/screens/fresh-books-import/index.scss +39 -0
- data/client/skr/screens/gl-accounts/GlAccounts.cjsx +31 -0
- data/client/skr/screens/gl-accounts/index.js +5 -0
- data/client/skr/screens/gl-transactions/GlTransactions.cjsx +46 -0
- data/client/skr/screens/gl-transactions/index.js +1 -0
- data/client/skr/screens/gl-transactions/index.scss +12 -0
- data/client/skr/screens/invoice/Invoice.cjsx +92 -0
- data/client/skr/screens/invoice/Payment.cjsx +28 -0
- data/client/skr/screens/invoice/index.js +5 -0
- data/client/skr/screens/locations/Locations.cjsx +31 -0
- data/client/skr/screens/locations/index.js +5 -0
- data/client/skr/screens/payment-category/PaymentCategory.cjsx +28 -0
- data/client/skr/screens/payment-category/index.js +5 -0
- data/client/skr/screens/payment-category/index.scss +9 -0
- data/client/skr/screens/payment-terms/PaymentTerms.cjsx +28 -0
- data/client/skr/screens/payment-terms/index.js +5 -0
- data/client/skr/screens/payment-terms/index.scss +9 -0
- data/client/skr/screens/payments/Payments.cjsx +59 -0
- data/client/skr/screens/payments/index.js +5 -0
- data/client/skr/screens/sales-order/SalesOrder.cjsx +68 -0
- data/client/skr/screens/sales-order/index.js +1 -5
- data/client/skr/screens/sku-maint/SkuMaint.cjsx +53 -0
- data/client/skr/screens/sku-maint/SkuUomList.cjsx +209 -0
- data/client/skr/screens/sku-maint/index.js +2 -5
- data/client/skr/screens/sku-maint/index.scss +37 -6
- data/client/skr/screens/time-invoicing/TimeInvoicing.cjsx +156 -0
- data/client/skr/screens/time-invoicing/index.js +5 -0
- data/client/skr/screens/time-invoicing/index.scss +7 -0
- data/client/skr/screens/time-tracking/EditEntry.cjsx +54 -0
- data/client/skr/screens/time-tracking/Entries.coffee +132 -0
- data/client/skr/screens/time-tracking/Header.cjsx +71 -0
- data/client/skr/screens/time-tracking/Popover.cjsx +70 -0
- data/client/skr/screens/time-tracking/PopoverMiniControls.cjsx +25 -0
- data/client/skr/screens/time-tracking/TimeTracking.cjsx +63 -0
- data/client/skr/screens/time-tracking/WeekSummary.cjsx +16 -0
- data/client/skr/screens/time-tracking/index.js +1 -0
- data/client/skr/screens/time-tracking/index.scss +126 -0
- data/client/skr/screens/vendor-maint/VendorMaint.cjsx +45 -0
- data/client/skr/screens/vendor-maint/index.js +1 -5
- data/client/skr/styles.scss +1 -13
- data/config/puma.rb +4 -0
- data/config/routes.rb +21 -9
- data/config/screens.rb +147 -32
- data/db/migrate/20140202194700_create_skr_gl_transaction_details.rb +35 -0
- data/db/migrate/20140220031800_create_skr_locations.rb +2 -0
- data/db/migrate/20140220190836_create_skr_vendors.rb +1 -0
- data/db/migrate/20140220203029_create_skr_customers.rb +3 -2
- data/db/migrate/20140224034759_create_skr_skus.rb +2 -3
- data/db/migrate/20140322223912_create_skr_sales_orders.rb +4 -3
- data/db/migrate/20140322223920_create_skr_so_lines.rb +4 -5
- data/db/migrate/20140323001446_create_so_details_view.rb +7 -5
- data/db/migrate/20140327202209_create_skr_pt_lines.rb +2 -2
- data/db/migrate/20140327214000_create_customer_project.rb +16 -0
- data/db/migrate/20140327223002_create_time_entries.rb +17 -0
- data/db/migrate/20140327224000_create_skr_invoices.rb +5 -1
- data/db/migrate/20140327224002_create_skr_inv_lines.rb +3 -1
- data/db/migrate/20140422024010_create_skr_inv_details_view.rb +1 -1
- data/db/migrate/20151121211323_create_customer_project_details_views.rb +31 -0
- data/db/migrate/20160216142845_create_gl_account_balances_view.rb +20 -0
- data/db/migrate/20160229002044_create_bank_accounts.rb +18 -0
- data/db/migrate/20160229041711_create_payments.rb +33 -0
- data/db/migrate/20160307022705_create_create_combined_uom_views.rb +18 -0
- data/db/schema.sql +639 -140
- data/db/seed/chart_of_accounts.yml +8 -6
- data/db/seed/payment_categories.yml +12 -0
- data/db/seed/skus.yml +32 -0
- data/db/seed.rb +21 -0
- data/lib/skr/access_roles.rb +19 -6
- data/lib/skr/concerns/has_sku_loc_lines.rb +0 -16
- data/lib/skr/concerns/inv_extensions.rb +24 -0
- data/lib/skr/concerns/is_sku_loc_line.rb +3 -4
- data/lib/skr/concerns/so_extensions.rb +8 -0
- data/lib/skr/concerns/visible_id_identifier.rb +1 -1
- data/lib/skr/db/migration_helpers.rb +2 -4
- data/lib/skr/extension.rb +11 -4
- data/lib/skr/handlers/fresh_books_import.rb +20 -0
- data/lib/skr/handlers/invoice_from_time_entries.rb +49 -0
- data/lib/skr/jobs/fresh_books/base.rb +54 -0
- data/lib/skr/jobs/fresh_books/import.rb +151 -0
- data/lib/skr/jobs/fresh_books/retrieve.rb +62 -0
- data/lib/skr/model.rb +5 -0
- data/lib/skr/models/address.rb +1 -1
- data/lib/skr/models/bank_account.rb +13 -0
- data/lib/skr/models/business_entity.rb +3 -0
- data/lib/skr/models/customer.rb +1 -1
- data/lib/skr/models/customer_project.rb +22 -0
- data/lib/skr/models/gl_account.rb +13 -3
- data/lib/skr/models/gl_period.rb +6 -0
- data/lib/skr/models/gl_posting.rb +7 -4
- data/lib/skr/models/gl_transaction.rb +19 -33
- data/lib/skr/models/ia_line.rb +1 -1
- data/lib/skr/models/inv_line.rb +33 -15
- data/lib/skr/models/invoice.rb +47 -20
- data/lib/skr/models/location.rb +7 -1
- data/lib/skr/models/payment.rb +49 -0
- data/lib/skr/models/payment_category.rb +11 -0
- data/lib/skr/models/payment_term.rb +1 -1
- data/lib/skr/models/por_line.rb +1 -1
- data/lib/skr/models/pt_line.rb +1 -1
- data/lib/skr/models/sales_order.rb +9 -9
- data/lib/skr/models/sku_loc.rb +1 -1
- data/lib/skr/models/sku_tran.rb +6 -11
- data/lib/skr/models/so_line.rb +22 -12
- data/lib/skr/models/time_entry.rb +36 -0
- data/lib/skr/models/uom.rb +11 -10
- data/lib/skr/models/user_proxy.rb +1 -1
- data/lib/skr/number.rb +25 -0
- data/lib/skr/print/form.rb +46 -0
- data/lib/skr/print/template.rb +48 -0
- data/lib/skr/print.rb +11 -0
- data/lib/skr/string.rb +11 -0
- data/lib/skr/version.rb +1 -1
- data/lib/skr.rb +9 -0
- data/spec/fixtures/skr/address.yml +164 -4
- data/spec/fixtures/skr/bank_account.yml +8 -0
- data/spec/fixtures/skr/customer.yml +30 -4
- data/spec/fixtures/skr/customer_project.yml +20 -0
- data/spec/fixtures/skr/gl_account.yml +19 -1
- data/spec/fixtures/skr/gl_period.yml +3 -0
- data/spec/fixtures/skr/gl_posting.yml +22 -1
- data/spec/fixtures/skr/gl_transaction.yml +4 -1
- data/spec/fixtures/skr/inv_line.yml +35 -0
- data/spec/fixtures/skr/invoice.yml +13 -2
- data/spec/fixtures/skr/location.yml +5 -0
- data/spec/fixtures/skr/payment.yml +10 -0
- data/spec/fixtures/skr/payment_category.yml +8 -0
- data/spec/fixtures/skr/payment_term.yml +37 -3
- data/spec/fixtures/skr/sales_order.yml +12 -1
- data/spec/fixtures/skr/sku.yml +78 -1
- data/spec/fixtures/skr/sku_loc.yml +42 -1
- data/spec/fixtures/skr/sku_tran.yml +24 -1
- data/spec/fixtures/skr/so_line.yml +32 -0
- data/spec/fixtures/skr/time_entry.yml +82 -0
- data/spec/fixtures/skr/uom.yml +52 -1
- data/spec/fixtures/skr/vendor.yml +28 -1
- data/spec/fixtures/stockor.png +0 -0
- data/spec/server/bank_account_spec.rb +10 -0
- data/spec/server/customer_project_spec.rb +10 -0
- data/spec/server/handlers/invoice_from_time_entries_spec.rb +49 -0
- data/spec/server/jobs/fresh_books/import_spec.rb +69 -0
- data/spec/server/jobs/fresh_books/retrieve_spec.rb +37 -0
- data/spec/server/models/address_spec.rb +4 -3
- data/spec/server/models/gl_transaction_spec.rb +3 -3
- data/spec/server/models/inv_line_spec.rb +83 -3
- data/spec/server/models/invoice_spec.rb +32 -3
- data/spec/server/models/payment_spec.rb +40 -0
- data/spec/server/models/sales_order_spec.rb +1 -1
- data/spec/server/models/so_line_spec.rb +3 -3
- data/spec/server/models/spec_helper_spec.rb +1 -1
- data/spec/server/payment_spec.rb +10 -0
- data/spec/server/print/form_spec.rb +47 -0
- data/spec/server/print/template_spec.rb +36 -0
- data/spec/server/spec_helper.rb +14 -1
- data/spec/server/time_entry_spec.rb +10 -0
- data/spec/skr/components/SkuLinesSpec.coffee +61 -0
- data/spec/skr/models/BankAccountSpec.coffee +5 -0
- data/spec/skr/models/CustomerProjectSpec.coffee +5 -0
- data/spec/skr/models/CustomerSpec.coffee +2 -2
- data/spec/skr/models/PaymentSpec.coffee +5 -0
- data/spec/skr/models/SalesOrderSpec.coffee +21 -5
- data/spec/skr/models/SoLineSpec.coffee +7 -2
- data/spec/skr/models/TimeEntrySpec.coffee +5 -0
- data/spec/skr/screens/bank-maint/BankMaintSpec.coffee +5 -0
- data/spec/skr/screens/customer-projects/CustomerProjectsSpec.coffee +5 -0
- data/spec/skr/screens/fresh-books-import/FreshBooksImportSpec.coffee +1 -0
- data/spec/skr/screens/gl-accounts/GlAccountsSpec.coffee +5 -0
- data/spec/skr/screens/invoice/InvoiceSpec.coffee +5 -0
- data/spec/skr/screens/locations/LocationsSpec.coffee +5 -0
- data/spec/skr/screens/payment-category/PaymentCategorySpec.coffee +5 -0
- data/spec/skr/screens/payment-terms/PaymentTermsSpec.coffee +5 -0
- data/spec/skr/screens/payments/PaymentsSpec.coffee +5 -0
- data/spec/skr/screens/time-invoicing/TimeInvoicingSpec.coffee +5 -0
- data/spec/skr/screens/time-tracking/TimeTrackingSpec.coffee +14 -0
- data/spec/vcr/freshbooks.yml +698 -0
- data/stockor.gemspec +5 -1
- data/templates/print/fonts/GnuMICR.otf +0 -0
- data/templates/print/layout.tex.erb +39 -0
- data/templates/print/packages/booktabs.sty +182 -0
- data/templates/print/packages/fancybox.sty +966 -0
- data/templates/print/packages/fancyhdr.sty +485 -0
- data/templates/print/packages/graphbox.sty +129 -0
- data/templates/print/packages/lastpage.sty +283 -0
- data/templates/print/packages/lastpage209.sty +70 -0
- data/templates/print/packages/marginnote.sty +412 -0
- data/templates/print/packages/multirow.sty +159 -0
- data/templates/print/packages/rotating.sty +282 -0
- data/templates/print/packages/tabu.sty +2557 -0
- data/templates/print/packages/textpos.sty +361 -0
- data/templates/print/packages/varwidth.sty +318 -0
- data/templates/print/partials/address.tex.erb +6 -0
- data/templates/print/partials/bill_to_ship_to.tex.erb +13 -0
- data/templates/print/partials/header.tex.erb +13 -0
- data/templates/print/partials/invoice_paid_state.tex.erb +2 -0
- data/templates/print/partials/old/inv_lines_grouping.tex.erb +8 -0
- data/templates/print/partials/old/labor_lines_footer.tex.erb +18 -0
- data/templates/print/partials/skus_table.tex.erb +32 -0
- data/templates/print/partials/skus_table_col_hdr.tex.erb +8 -0
- data/templates/print/partials/skus_table_footer.tex.erb +5 -0
- data/templates/print/partials/skus_table_group_footer.tex.erb +4 -0
- data/templates/print/partials/skus_table_invoice_footer.tex.erb +25 -0
- data/templates/print/partials/skus_table_invoice_info_line.tex.erb +16 -0
- data/templates/print/partials/skus_table_labor_col_hdr.tex.erb +8 -0
- data/templates/print/partials/skus_table_labor_group_footer.tex.erb +7 -0
- data/templates/print/partials/skus_table_labor_line.tex.erb +11 -0
- data/templates/print/partials/skus_table_line.tex.erb +6 -0
- data/templates/print/partials/skus_table_other_charge_lines.tex.erb +7 -0
- data/templates/print/partials/so_info_line.tex.erb +14 -0
- data/templates/print/types/invoice/default.tex.erb +13 -0
- data/templates/print/types/invoice/labor.tex.erb +33 -0
- data/templates/print/types/payment/default.tex.erb +64 -0
- data/templates/print/types/sales-order/default.tex.erb +8 -0
- metadata +252 -15
- data/client/skr/components/address/address.html +0 -20
- data/client/skr/models/mixins/CodeField.coffee +0 -5
- data/client/skr/screens/customer-maint/index.scss +0 -11
- data/client/skr/screens/customer-maint/layout.html +0 -32
- data/client/skr/screens/sales-order/SalesOrder.coffee +0 -30
- data/client/skr/screens/sales-order/index.scss +0 -8
- data/client/skr/screens/sales-order/layout.html +0 -30
- data/client/skr/screens/sku-maint/SkuMaint.coffee +0 -18
- data/client/skr/screens/sku-maint/layout.html +0 -16
- data/client/skr/screens/vendor-maint/VendorMaint.coffee +0 -28
- data/client/skr/screens/vendor-maint/index.scss +0 -8
- data/client/skr/screens/vendor-maint/layout.html +0 -32
@@ -15,7 +15,7 @@
|
|
15
15
|
number: 1115
|
16
16
|
name: Inventory in Transist
|
17
17
|
description: Inventory on a transfer between locations
|
18
|
-
|
18
|
+
|
19
19
|
-
|
20
20
|
number: 1200
|
21
21
|
name: Accounts Receivable
|
@@ -25,7 +25,7 @@
|
|
25
25
|
name: Prepayment Revenue
|
26
26
|
description: Amounts received in advance of providing goods and services but not yet delivered.
|
27
27
|
-
|
28
|
-
number: 1750
|
28
|
+
number: 1750
|
29
29
|
name: Buildings
|
30
30
|
description: Cost to purchase or construct buildings for use by the company.
|
31
31
|
-
|
@@ -50,7 +50,7 @@
|
|
50
50
|
-
|
51
51
|
number: 2300
|
52
52
|
name: Wages Payable
|
53
|
-
description: Amount owed to employees for hours worked but not yet paid.
|
53
|
+
description: Amount owed to employees for hours worked but not yet paid.
|
54
54
|
|
55
55
|
-
|
56
56
|
number: 2400
|
@@ -62,7 +62,7 @@
|
|
62
62
|
name: Interest Payable
|
63
63
|
description: Amount owed for interest on Notes Payable.
|
64
64
|
|
65
|
-
-
|
65
|
+
-
|
66
66
|
number: 2600
|
67
67
|
name: Inventory Receipts Clearing
|
68
68
|
description: Inventory received but vendor invoice not yet confirmed
|
@@ -131,7 +131,10 @@
|
|
131
131
|
number: 6420
|
132
132
|
name: Inbound Shipping Expense
|
133
133
|
description: Cost of vendors shipping goods to us
|
134
|
-
|
134
|
+
-
|
135
|
+
number: 6450
|
136
|
+
name: Misc Expense
|
137
|
+
description: Miscellaneous costs incurred
|
135
138
|
-
|
136
139
|
number: 6500
|
137
140
|
name: Depreciation Expense
|
@@ -165,4 +168,3 @@
|
|
165
168
|
number: 8100
|
166
169
|
name: Non operating Expense
|
167
170
|
description: Expense incurred by other means
|
168
|
-
|
data/db/seed/skus.yml
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
-
|
2
|
+
code: MISC
|
3
|
+
description: Miscellaneous Item
|
4
|
+
default_uom_code: EA
|
5
|
+
is_other_charge: false
|
6
|
+
does_track_inventory: false
|
7
|
+
gl_asset_account: 1110
|
8
|
+
can_backorder: false
|
9
|
+
-
|
10
|
+
code: LABOR
|
11
|
+
description: Work performed
|
12
|
+
default_uom_code: HOUR
|
13
|
+
is_other_charge: false
|
14
|
+
does_track_inventory: false
|
15
|
+
gl_asset_account: 6200
|
16
|
+
can_backorder: false
|
17
|
+
-
|
18
|
+
code: TAX
|
19
|
+
description: Sales Tax
|
20
|
+
is_other_charge: true
|
21
|
+
does_track_inventory: false
|
22
|
+
default_uom_code: EA
|
23
|
+
gl_asset_account: 1900
|
24
|
+
can_backorder: false
|
25
|
+
-
|
26
|
+
code: SHIP
|
27
|
+
description: Sales Ship
|
28
|
+
is_other_charge: true
|
29
|
+
does_track_inventory: false
|
30
|
+
default_uom_code: EA
|
31
|
+
gl_asset_account: 6410
|
32
|
+
can_backorder: false
|
data/db/seed.rb
CHANGED
@@ -27,6 +27,27 @@ module Skr
|
|
27
27
|
YAML::load( seeds_path.join('payment_terms.yml').read ).each do | acct_data |
|
28
28
|
PaymentTerm.where(code: acct_data['code'].to_s).any? || PaymentTerm.create!(acct_data)
|
29
29
|
end
|
30
|
+
|
31
|
+
YAML::load( seeds_path.join('skus.yml').read ).each do | sku_data |
|
32
|
+
unless Sku.where(code: sku_data['code'].to_s).any?
|
33
|
+
glasset = GlAccount.where(number: sku_data.delete('gl_asset_account')).first
|
34
|
+
sku = Sku.new(sku_data)
|
35
|
+
sku.uoms << Uom.new(code: sku_data['default_uom_code'],
|
36
|
+
size:1, price: '0.0')
|
37
|
+
sku.gl_asset_account = glasset
|
38
|
+
sku.save!
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
YAML::load( seeds_path.join('payment_categories.yml').read ).each do | category_data |
|
43
|
+
next if Skr::PaymentCategory.exists?(code: category_data['code'])
|
44
|
+
Skr::PaymentCategory.create!(
|
45
|
+
code: category_data['code'],
|
46
|
+
name: category_data['name'],
|
47
|
+
gl_account: GlAccount.find_by_number(category_data['gl_account'])
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
30
51
|
end
|
31
52
|
|
32
53
|
end
|
data/lib/skr/access_roles.rb
CHANGED
@@ -4,21 +4,27 @@ require_relative "model"
|
|
4
4
|
module Lanes::Access
|
5
5
|
module Roles
|
6
6
|
|
7
|
-
|
8
7
|
# re-open the exising Support role
|
9
8
|
class Support
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
read Skr::Invoice,
|
10
|
+
Skr::Customer,
|
11
|
+
Skr::Sku
|
13
12
|
|
13
|
+
grant Skr::SalesOrder,
|
14
|
+
Skr::TimeEntry
|
14
15
|
end
|
15
16
|
|
16
|
-
|
17
17
|
class Accounting < Lanes::Access::Role
|
18
18
|
grant Skr::Customer,
|
19
19
|
Skr::PaymentTerm,
|
20
|
+
Skr::CustomerProject,
|
20
21
|
Skr::Sku,
|
21
|
-
Skr::SalesOrder
|
22
|
+
Skr::SalesOrder,
|
23
|
+
Skr::TimeEntry,
|
24
|
+
Skr::GlTransaction,
|
25
|
+
Skr::BankAccount,
|
26
|
+
Skr::Payment
|
27
|
+
|
22
28
|
lock_writes Skr::Customer, :terms
|
23
29
|
lock Skr::Sku, :gl_asset_account
|
24
30
|
lock Skr::Customer, :gl_receivables_account
|
@@ -31,6 +37,13 @@ module Lanes::Access
|
|
31
37
|
Skr::SalesOrder
|
32
38
|
end
|
33
39
|
|
40
|
+
class Workforce < Lanes::Access::Role
|
41
|
+
read Skr::Customer,
|
42
|
+
Skr::Sku
|
43
|
+
grant Skr::SalesOrder,
|
44
|
+
Skr::Invoice,
|
45
|
+
Skr::TimeEntry
|
46
|
+
end
|
34
47
|
end
|
35
48
|
|
36
49
|
Role.grant_global_access(Skr::Address)
|
@@ -7,22 +7,6 @@ module Skr
|
|
7
7
|
|
8
8
|
module InstanceMethods
|
9
9
|
|
10
|
-
def other_charge_lines
|
11
|
-
self.lines.select{|l| l.sku.is_other_charge? }
|
12
|
-
end
|
13
|
-
|
14
|
-
def regular_lines
|
15
|
-
self.lines.reject{|l| l.sku.is_other_charge? }
|
16
|
-
end
|
17
|
-
|
18
|
-
def regular_lines_total
|
19
|
-
self.regular_lines.sum{|l|l.extended_price}
|
20
|
-
end
|
21
|
-
|
22
|
-
def subtotal
|
23
|
-
self.regular_lines.inject(0){|sum,line| sum + line.extended_price }
|
24
|
-
end
|
25
|
-
|
26
10
|
def total
|
27
11
|
if total = self.read_attribute('total')
|
28
12
|
BigDecimal.new(total)
|
@@ -5,6 +5,22 @@ module Skr
|
|
5
5
|
|
6
6
|
module Lines
|
7
7
|
|
8
|
+
def other_charge
|
9
|
+
select{|l| l.sku.is_other_charge? }
|
10
|
+
end
|
11
|
+
|
12
|
+
def regular
|
13
|
+
reject{|l| l.sku.is_other_charge? }
|
14
|
+
end
|
15
|
+
|
16
|
+
def product
|
17
|
+
reject{|l| l.time_entry }
|
18
|
+
end
|
19
|
+
|
20
|
+
def time_entry
|
21
|
+
select{|l| l.time_entry }
|
22
|
+
end
|
23
|
+
|
8
24
|
def from_pick_ticket!
|
9
25
|
proxy_association.owner.pick_ticket.lines.each do | line |
|
10
26
|
build({ pt_line: line, qty: line.qty_to_ship })
|
@@ -17,6 +33,14 @@ module Skr
|
|
17
33
|
end
|
18
34
|
end
|
19
35
|
|
36
|
+
def ea_qty
|
37
|
+
if proxy_association.loaded?
|
38
|
+
inject(0){ | sum, il | sum+(il.qty*il.uom_size) }
|
39
|
+
else
|
40
|
+
sum('qty*uom_size')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
20
44
|
end
|
21
45
|
|
22
46
|
end
|
@@ -48,15 +48,14 @@ module Skr
|
|
48
48
|
|
49
49
|
if parent
|
50
50
|
before_create do
|
51
|
-
self.position ||=
|
51
|
+
self.position ||= self.send( parent ).lines.max_by{|l|
|
52
|
+
l.position || 0
|
53
|
+
}.position.to_i + 1
|
52
54
|
end
|
53
55
|
end
|
54
|
-
|
55
56
|
export_methods :extended_price, :optional=>false
|
56
|
-
|
57
57
|
end
|
58
58
|
|
59
|
-
|
60
59
|
end
|
61
60
|
|
62
61
|
end
|
@@ -11,7 +11,7 @@ module Skr
|
|
11
11
|
# setup the visible id to the next available #{Skr::SequentialId}
|
12
12
|
# @return [Integer] the assigned ID
|
13
13
|
def assign_visible_id!
|
14
|
-
self.visible_id
|
14
|
+
self.visible_id ||= Skr::SequentialId.next_for( self.class )
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
@@ -12,10 +12,8 @@ module Skr
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def skr_visible_id
|
15
|
-
column( :visible_id, :
|
16
|
-
skr_extra_indexes['visible_id'] = {
|
17
|
-
function: 'CAST(visible_id AS VARCHAR)'
|
18
|
-
}
|
15
|
+
column( :visible_id, :string, :null=>false )
|
16
|
+
skr_extra_indexes['visible_id'] = {}
|
19
17
|
end
|
20
18
|
|
21
19
|
def skr_state
|
data/lib/skr/extension.rb
CHANGED
@@ -1,14 +1,16 @@
|
|
1
1
|
require 'lanes/access/extension'
|
2
|
-
|
3
2
|
module Skr
|
4
3
|
|
5
4
|
class Extension < Lanes::Extensions::Definition
|
6
5
|
|
7
6
|
identifier "skr"
|
8
|
-
|
7
|
+
title "Stockor"
|
9
8
|
root_path Pathname.new(__FILE__).dirname.join("..","..").expand_path
|
10
9
|
|
11
|
-
components 'record-finder', 'select-field'
|
10
|
+
components 'record-finder', 'select-field', 'calendar'
|
11
|
+
client_js_aliases({
|
12
|
+
'SC' => 'window.Lanes.Skr.Components'
|
13
|
+
})
|
12
14
|
|
13
15
|
def client_bootstrap_data(view)
|
14
16
|
gl_accounts = Skr::GlAccount.all.as_json
|
@@ -17,10 +19,15 @@ module Skr
|
|
17
19
|
account = gl_accounts.detect{|gla|gla['number'] == number}
|
18
20
|
[code, account ? account['id'] : 0]
|
19
21
|
}],
|
20
|
-
gl_accounts: gl_accounts
|
22
|
+
gl_accounts: gl_accounts,
|
23
|
+
payment_terms: Skr::PaymentTerm.all.as_json,
|
24
|
+
locations: Skr::Location.all.as_json,
|
25
|
+
templates: Skr::Print::Template.as_json
|
21
26
|
}
|
22
27
|
end
|
23
28
|
|
24
29
|
end
|
25
30
|
|
26
31
|
end
|
32
|
+
|
33
|
+
require 'skr'
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'ruby-freshbooks'
|
2
|
+
|
3
|
+
module Skr::Handlers
|
4
|
+
|
5
|
+
class FreshBooksImport
|
6
|
+
|
7
|
+
def self.handler
|
8
|
+
lambda do
|
9
|
+
resp = if data['stage'] == 'fetch'
|
10
|
+
Skr::Jobs::FreshBooks::Retrieve.from_request(data)
|
11
|
+
else
|
12
|
+
Skr::Jobs::FreshBooks::Import.from_request(data)
|
13
|
+
end
|
14
|
+
json_reply resp
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Skr
|
2
|
+
module Handlers
|
3
|
+
class InvoiceFromTimeEntries
|
4
|
+
|
5
|
+
def initialize(project_id, entry_ids, options = {})
|
6
|
+
@project = CustomerProject.find(project_id)
|
7
|
+
@entry_ids = entry_ids
|
8
|
+
|
9
|
+
@location = Location.default # should be set on project maybe?
|
10
|
+
@sku_loc = @project.sku.sku_locs.find_by(location: @location)
|
11
|
+
@options = options
|
12
|
+
end
|
13
|
+
|
14
|
+
def build_invoice
|
15
|
+
invoice = Invoice.new(
|
16
|
+
customer_project: @project,
|
17
|
+
customer: @project.customer,
|
18
|
+
po_num: @options['po_num'] || @project.po_num,
|
19
|
+
notes: @options['notes']
|
20
|
+
)
|
21
|
+
@entry_ids.each do | entry_id |
|
22
|
+
entry = TimeEntry.find(entry_id)
|
23
|
+
invoice.lines.build(
|
24
|
+
time_entry: entry,
|
25
|
+
sku_loc: @sku_loc,
|
26
|
+
price: @project.rates['hourly'],
|
27
|
+
description: entry.description,
|
28
|
+
qty: ((entry.end_at - entry.start_at) / 1.hour)
|
29
|
+
)
|
30
|
+
end
|
31
|
+
invoice
|
32
|
+
end
|
33
|
+
|
34
|
+
|
35
|
+
def self.handler
|
36
|
+
lambda do
|
37
|
+
wrap_reply do
|
38
|
+
builder = InvoiceFromTimeEntries.new(
|
39
|
+
data['customer_project_id'], data['time_entry_ids'], data
|
40
|
+
)
|
41
|
+
invoice = builder.build_invoice
|
42
|
+
std_api_reply :create, { invoice: invoice }, success: invoice.save
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'ruby-freshbooks'
|
2
|
+
|
3
|
+
module Skr
|
4
|
+
module Jobs
|
5
|
+
module FreshBooks
|
6
|
+
|
7
|
+
class Base < Lanes::Job
|
8
|
+
STEPS = %w{staff clients projects time_entries invoices}
|
9
|
+
|
10
|
+
attr_reader :fb
|
11
|
+
def resp_data_for_req_type(type, resp)
|
12
|
+
if type == 'staff'
|
13
|
+
data = resp['staff_members']
|
14
|
+
data[type]=data.delete('member')
|
15
|
+
data
|
16
|
+
else
|
17
|
+
resp[type.pluralize]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def fetch_each(reqtype)
|
22
|
+
Enumerator.new { | enum |
|
23
|
+
page = last_page = 1
|
24
|
+
while page <= last_page
|
25
|
+
resp = fb.__send__(reqtype).list(per_page: 25, page: page)
|
26
|
+
data = resp_data_for_req_type(reqtype, resp)
|
27
|
+
last_page = data['pages'].to_i
|
28
|
+
page += 1
|
29
|
+
Array.wrap(data[reqtype]).each{|record|
|
30
|
+
enum.yield record
|
31
|
+
}
|
32
|
+
end
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def process_each_type(account, token)
|
38
|
+
@fb = ::FreshBooks::Client.new("#{account}.freshbooks.com", token)
|
39
|
+
output = {}
|
40
|
+
@ignored_ids ||= {}
|
41
|
+
STEPS.each_with_index do | step, index |
|
42
|
+
type = step.singularize
|
43
|
+
output[step] = fetch_each( type ).map { | record |
|
44
|
+
send("process_#{type}", record)
|
45
|
+
}.reject(&:nil?)
|
46
|
+
yield output, index
|
47
|
+
end
|
48
|
+
output
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,151 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
module Skr::Jobs::FreshBooks
|
4
|
+
|
5
|
+
class Import < Base
|
6
|
+
def to_name(r)
|
7
|
+
[r['first_name'], r['last_name']].compact.join(' ')
|
8
|
+
end
|
9
|
+
|
10
|
+
def customer_for_fb_id(id)
|
11
|
+
code = @customer_codes[id]
|
12
|
+
if code
|
13
|
+
Skr::Customer.find_by_code(code)
|
14
|
+
else
|
15
|
+
Skr::Customer.where("options ->>'freshbooks_id' = ?", id).first
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def is_ignored?(type, id)
|
21
|
+
@ignored_ids[type] && @ignored_ids[type].include?(id)
|
22
|
+
end
|
23
|
+
|
24
|
+
def get_user(staff_id)
|
25
|
+
if @user_mappings[staff_id]
|
26
|
+
Lanes::User.find(@user_mappings[staff_id])
|
27
|
+
else
|
28
|
+
Lanes::User.where("options ->>'freshbooks_id' = ?", staff_id).first
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def process_client(r)
|
33
|
+
return nil if is_ignored?('clients', r['client_id'])
|
34
|
+
code = @customer_codes[ r['client_id'] ]
|
35
|
+
return if code and Skr::Customer.find_by_code(code)
|
36
|
+
Skr::Customer.create(
|
37
|
+
code: code,
|
38
|
+
name: r['organization'], options: { freshbooks_id: r['client_id'] },
|
39
|
+
notes: r['notes'], credit_limit: r['credit'],
|
40
|
+
billing_address_attributes: {
|
41
|
+
name: to_name(r),
|
42
|
+
email: r['email'], phone: r['work_phone'] || r['mobile'] || r['home_phone'],
|
43
|
+
line1: r['p_street1'], line2: r['p_street2'], city: r['p_city'],
|
44
|
+
state: r['p_state'], postal_code: r['p_code']
|
45
|
+
},
|
46
|
+
shipping_address_attributes: {
|
47
|
+
name: to_name(r),
|
48
|
+
email: r['email'], phone: r['mobile'] || r['work_phone'] || r['home_phone'],
|
49
|
+
line1: r['s_street1'], line2: r['s_street2'], city: r['s_city'],
|
50
|
+
state: r['s_state'], postal_code: r['s_code']
|
51
|
+
}
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
def process_staff(r)
|
56
|
+
return nil if is_ignored?('staff', r['staff_id']) or @user_mappings[r['staff_id']]
|
57
|
+
Lanes::User.create(
|
58
|
+
login: r['username'],
|
59
|
+
name: to_name(r),
|
60
|
+
password: 'password',
|
61
|
+
email: r['email'],
|
62
|
+
options: { freshbooks_id: r['staff_id'] },
|
63
|
+
role_names: ['workforce']
|
64
|
+
)
|
65
|
+
end
|
66
|
+
|
67
|
+
def process_project(r)
|
68
|
+
return nil if is_ignored?('projects', r['project_id'])
|
69
|
+
Skr::CustomerProject.create(
|
70
|
+
name: r['name'], description: r['description'],
|
71
|
+
sku: Skr::Sku.find_by(code: 'LABOR'),
|
72
|
+
customer: customer_for_fb_id(r['client_id']),
|
73
|
+
options: { freshbooks_id: r['project_id'] },
|
74
|
+
rates: {"hourly": r['rate']},
|
75
|
+
)
|
76
|
+
end
|
77
|
+
|
78
|
+
def process_time_entry(r)
|
79
|
+
return nil if is_ignored?('time_entries', r['time_entry_id'])
|
80
|
+
Skr::TimeEntry.create(
|
81
|
+
is_invoiced: r['billed'] == '1',
|
82
|
+
options: { freshbooks_id: r['time_entry_id'] },
|
83
|
+
customer_project: Skr::CustomerProject.where("options ->>'freshbooks_id' = ?", r['project_id']).first,
|
84
|
+
description: r['notes'],
|
85
|
+
start_at: DateTime.parse(r['date']) + 8.hours,
|
86
|
+
end_at: DateTime.parse(r['date']) + 8.hours + r['hours'].to_i.hours,
|
87
|
+
lanes_user: get_user(r['staff_id'])
|
88
|
+
)
|
89
|
+
end
|
90
|
+
|
91
|
+
def process_invoice(r)
|
92
|
+
return nil if is_ignored?('invoices', r['invoice_id'])
|
93
|
+
|
94
|
+
inv = Skr::Invoice.create(
|
95
|
+
visible_id: r['number'].sub(/^0+/,''),
|
96
|
+
options: { freshbooks_id: r['invoice_id'] },
|
97
|
+
customer: customer_for_fb_id(r['client_id']),
|
98
|
+
location: Skr::Location.default,
|
99
|
+
po_num: r['po_number'], notes: r['notes'],
|
100
|
+
invoice_date: DateTime.parse(r['date']),
|
101
|
+
terms: Skr::PaymentTerm.find_by(days: r['terms'].to_s[/\d+/, 0] || 30),
|
102
|
+
billing_address_attributes: {
|
103
|
+
name: to_name(r),
|
104
|
+
email: r['email'], phone: r['mobile'] || r['work_phone'] || r['home_phone'],
|
105
|
+
line1: r['p_street1'], line2: r['p_street2'], city: r['p_city'],
|
106
|
+
state: r['p_state'], postal_code: r['p_code']
|
107
|
+
},
|
108
|
+
lines_attributes: Array.wrap(r['lines']['line']).map { | l |
|
109
|
+
is_time = 'Time' == l['type']
|
110
|
+
if l['name'] or l['description'] # blank name == blank line
|
111
|
+
sku = Skr::Sku.find_by(code: is_time ? 'LABOR' : 'MISC')
|
112
|
+
invl = {
|
113
|
+
sku_loc: sku.sku_locs.default,
|
114
|
+
price: l['unit_cost'],
|
115
|
+
description: l['description'],
|
116
|
+
qty: l['quantity']
|
117
|
+
}
|
118
|
+
if l.has_key?('time_entries')
|
119
|
+
invl['time_entry'] =
|
120
|
+
Skr::TimeEntry.find_by("options ->>'freshbooks_id' = ?",
|
121
|
+
l['time_entries']['time_entry']['time_entry_id'])
|
122
|
+
end
|
123
|
+
invl
|
124
|
+
end
|
125
|
+
}.compact
|
126
|
+
)
|
127
|
+
if r['paid'].to_f > 0
|
128
|
+
inv.update_attributes(amount_paid: r['paid'])
|
129
|
+
end
|
130
|
+
inv
|
131
|
+
end
|
132
|
+
|
133
|
+
def perform(data)
|
134
|
+
@ignored_ids = data['ignored_ids'] || {}
|
135
|
+
@user_mappings = data['user_mappings'] || {}
|
136
|
+
@customer_codes = data['customer_codes'] || {}
|
137
|
+
Skr::Invoice.transaction do
|
138
|
+
process_each_type(data['domain'], data['api_key']) do | output, index |
|
139
|
+
save_progress(output, (index+1).to_f / STEPS.length)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
self
|
143
|
+
end
|
144
|
+
|
145
|
+
def self.from_request(req)
|
146
|
+
Lanes::Job.api_status_message self.perform_later(req)
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require_relative 'base'
|
2
|
+
|
3
|
+
module Skr::Jobs::FreshBooks
|
4
|
+
|
5
|
+
class Retrieve < Base
|
6
|
+
|
7
|
+
def process_client(rec)
|
8
|
+
rec.slice(*%w{ client_id organization first_name last_name})
|
9
|
+
end
|
10
|
+
|
11
|
+
def process_project(rec)
|
12
|
+
rec.slice(*%w{project_id name description})
|
13
|
+
end
|
14
|
+
|
15
|
+
def process_invoice(rec)
|
16
|
+
rec.slice(*%w{invoice_id client_id number amount po_number notes status})
|
17
|
+
end
|
18
|
+
|
19
|
+
def process_time_entry(rec)
|
20
|
+
if rec['billed'] == '1'
|
21
|
+
nil
|
22
|
+
else
|
23
|
+
rec.slice(*%w{ time_entry_id staff_id project_id hours date notes})
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def process_staff(r)
|
28
|
+
r.slice(*%w{staff_id username first_name last_name email})
|
29
|
+
end
|
30
|
+
|
31
|
+
def perform(account, token)
|
32
|
+
process_each_type(account, token) do | output, index |
|
33
|
+
save_progress(output, (index+1).to_f / STEPS.length)
|
34
|
+
end
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.from_request(req)
|
39
|
+
fb = ::FreshBooks::Client.new("#{req['domain']}.freshbooks.com", req['api_key'])
|
40
|
+
errors = nil
|
41
|
+
begin
|
42
|
+
# make a test api call to validate authentication
|
43
|
+
resp = fb.client.list(per_page: 1)
|
44
|
+
errors = {access: resp['error']} if resp['error']
|
45
|
+
rescue SocketError
|
46
|
+
errors = {network: 'Unable to resolve account'}
|
47
|
+
end
|
48
|
+
if errors
|
49
|
+
return {success: false, data: {}, errors: errors}
|
50
|
+
else
|
51
|
+
job = self.perform_later(req['domain'], req['api_key'])
|
52
|
+
return {
|
53
|
+
success: true, message: 'Import Validation Started', data: {
|
54
|
+
job: Lanes::Job.status_for_id(job.job_id)
|
55
|
+
}
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
data/lib/skr/model.rb
CHANGED
@@ -49,4 +49,9 @@ module Skr
|
|
49
49
|
autoload :Vendor, "skr/models/vendor"
|
50
50
|
autoload :VoLine, "skr/models/vo_line"
|
51
51
|
autoload :Voucher, "skr/models/voucher"
|
52
|
+
autoload :TimeEntry, "skr/models/time_entry"
|
53
|
+
autoload :CustomerProject, "skr/models/customer_project"
|
54
|
+
autoload :BankAccount, "skr/models/bank_account"
|
55
|
+
autoload :PaymentCategory, "skr/models/payment_category"
|
56
|
+
autoload :Payment, "skr/models/payment"
|
52
57
|
end
|