Compare commits

..

183 Commits
0.7.2 ... 0.7.3

Author SHA1 Message Date
Rob Harrington
9163b0c1ad Adding missing equals sign to test for equality in permalink migration 2015-01-28 11:37:02 +11:00
Rob Harrington
fd9f65f1b6 Merge branch 'shopfront-filters' into shop-url 2015-01-28 10:57:11 +11:00
Rob Harrington
713999c1d8 Merge branch 'master' into shop-url 2015-01-28 10:53:42 +11:00
Rob Harrington
21db56ce6c Rollback angularjs upgrade 2015-01-28 08:41:14 +11:00
Rob Harrington
adbe127e76 Revert "Update bindonce"
This reverts commit 48dc85cfc2.
2015-01-25 14:08:29 +11:00
Lynne Davis
3c4ad4121f LD adding whitespace to get my master version back in line with origin 2015-01-22 14:00:48 +00:00
Lynne Davis
8e8f38e484 app/controllers/spree/admin/reports_controller_decorator.rb 2015-01-22 12:01:20 +00:00
Rob Harrington
b429be707c Split out payment and shipping methods from admin enterprises controller as services 2015-01-22 12:19:41 +11:00
Rob Harrington
4829e59663 Fixing checkout controller spec 2015-01-22 10:46:31 +11:00
Rob Harrington
d12fdd23fb Fixing navcheck callback 2015-01-22 10:46:01 +11:00
Rob Harrington
b0a29801b6 Making spec controller product request spec a little bit more robust 2015-01-22 10:20:03 +11:00
Rob Harrington
6ebd58b67d Updating home spec to reflect new shopfront url 2015-01-22 10:19:47 +11:00
Rob Harrington
0791cc3c2a Making sure that we have a .path() in HashNavigation 2015-01-22 10:19:47 +11:00
Rob Harrington
76acbb6159 Empty arrays are no longer considered falsy by angular.js parser (see bdfc9c02d0) 2015-01-22 10:19:47 +11:00
Rob Harrington
d7ea81e821 Prevent default form action from submitting ordercycle forms 2015-01-22 10:19:47 +11:00
Rob Harrington
9245af6a8f Producer properties routes use enterprise permalink 2015-01-22 10:19:47 +11:00
Rob Harrington
36430d3bad Enterprise permalink generator handles blank permalink case 2015-01-22 10:19:46 +11:00
Rob Harrington
7520552fd7 Removing spec for testing empty permalink, since we now force permalink to be created when empty 2015-01-22 10:19:46 +11:00
Rob Harrington
6991e5e6b1 Finally got all callbacks available to all action that need them 2015-01-22 10:19:46 +11:00
Rob Harrington
42d6695264 Fix permalink migration to handle blank auto-generated permalinks and fixed down migration 2015-01-22 10:19:45 +11:00
Rob Harrington
4d26b3d648 Make unused cart_controller happy 2015-01-22 10:19:45 +11:00
Rob Harrington
177181cd75 CurrentUser always returns a factory 2015-01-22 10:19:45 +11:00
Rob Harrington
4baa205cf9 before_filters for enterprise controller are run in the correct order, and put inside the shop action 2015-01-22 10:19:45 +11:00
Rob Harrington
60313f7a6a Replace delete with parameterize 2015-01-22 10:19:45 +11:00
Rob Harrington
3e5ea3fe63 Adding automatic permalink generation on enterprise creation 2015-01-22 10:19:45 +11:00
Rob Harrington
b98c01b280 Updating permalink controller specs 2015-01-22 10:19:44 +11:00
Rob Harrington
ff624e83eb Require distributor in enterprise controller, so that everything actually works 2015-01-22 10:19:44 +11:00
Rob Harrington
48dc85cfc2 Update bindonce 2015-01-22 10:19:44 +11:00
Rob Harrington
a0990c107f Moving navigation check to controller 2015-01-22 10:19:44 +11:00
Rob Harrington
585c061fb0 Upgrade angularjs 2015-01-22 10:19:44 +11:00
Rob Harrington
83726eba63 Refactoring permalink checker to handle multiple requests elegantly 2015-01-22 10:19:43 +11:00
Rob Harrington
7ad9fdf0be Cleaning permalink before checking 2015-01-22 10:19:43 +11:00
Rob Harrington
6b10a4a775 Restoring enterprise permalinks when they cause errors 2015-01-22 10:19:43 +11:00
Rob Harrington
4088bdc236 Clean up permalink checker 2015-01-22 10:19:43 +11:00
Rob Harrington
9b78963d5a Adding a javascript interface for checking permalinks and user input on enterprise console 2015-01-22 10:19:43 +11:00
Rob Harrington
3ec3441cfa Replacing all uses of the old enterprise shop url helper 2015-01-22 10:19:43 +11:00
Rob Harrington
39889390ef Altering shop page routing so that shop url is copy-and-pastable 2015-01-22 10:19:42 +11:00
Rob Harrington
c3659612ed enterprise routes use permalink 2015-01-22 10:19:42 +11:00
Rob Harrington
7a6cd98646 Fixing failing spec, missing permalink 2015-01-22 10:19:42 +11:00
Rob Harrington
9286c82b43 Removing obsolete methods 2015-01-22 10:19:42 +11:00
Rob Harrington
c330e49a7f Moving permalink check action to enterprise controller 2015-01-22 10:19:42 +11:00
Rob Harrington
e2268e53bb Adding action to check uniquness of enterprise permalink against existing routes 2015-01-22 10:19:41 +11:00
Rob Harrington
9f0aeb5adf Adding unique permalink to enterprises 2015-01-22 10:19:41 +11:00
Rohan Mitchell
41e42c78c4 Update spec link name 2015-01-16 17:25:38 +11:00
summerscope
1753432f36 Adding new loading animation to replace ugly and large gif 2015-01-16 17:06:40 +11:00
summerscope
0f8809abfc Merge branch 'master' into shopfront-filters 2015-01-16 16:12:34 +11:00
Rob Harrington
1d80bee595 Cart item total reflects total number of items in the cart 2015-01-16 16:06:51 +11:00
summerscope
d04e843315 kill unused line 2015-01-16 16:01:17 +11:00
summerscope
c0eb902eef Turn off text shadow for buttons on popover for top nav 2015-01-16 16:00:18 +11:00
Rob Harrington
2c307f09c3 Changing edit cart button to link 2015-01-16 15:47:56 +11:00
summerscope
23fc428d95 Move spinner icon to left of text 2015-01-16 14:57:30 +11:00
summerscope
3bd77c74a5 Improve logic on shopping cart button to add meaningful labels for various states 2015-01-16 14:57:09 +11:00
summerscope
8334ff736b Styling for shopping cart buttons and spinner 2015-01-16 13:27:34 +11:00
summerscope
51687b5c2c Tweak language and styling for the CTA buttons taking users to shopping cart and checkout pages 2015-01-16 13:27:16 +11:00
summerscope
21108b34b6 Add new animation for spinning 2015-01-16 13:26:40 +11:00
summerscope
2a21889216 Remove border on product thumbnail to clean up UI 2015-01-16 13:06:30 +11:00
summerscope
b451b94fd1 Improving styling on large thumbnail view of product images 2015-01-16 13:06:02 +11:00
summerscope
d2d3a577ea Merging master into this branch to make it easy to pull for staging push 2015-01-15 17:38:35 +11:00
Rob Harrington
b3e67fa164 Take two on disabled logic 2015-01-15 17:34:04 +11:00
Rob Harrington
ac34da4f24 Altering logic around disabled state for 'Your Shopping Cart' button 2015-01-15 17:19:48 +11:00
summerscope
d2277999cc Undo change of logic on disabled state on Shopping cart button 2015-01-15 17:13:10 +11:00
summerscope
cdd6c2daf2 Styling product summary row to allow for hiding product thumb at a larger break point 2015-01-15 16:46:55 +11:00
summerscope
4a881a5aa5 Turn off product thumb at a larger break point 2015-01-15 16:46:18 +11:00
summerscope
d5d218c450 Make taxon flag smaller for smallest device breakpoint 2015-01-15 16:45:54 +11:00
summerscope
f8622be21d Adding in new color variable 2015-01-15 16:45:29 +11:00
summerscope
676e7cb4d6 Make taxon flag 2 cols for small devices 2015-01-15 16:45:09 +11:00
summerscope
1dfbc88813 Change logic on disabled class on Your shopping cart button as this was swapped the wrong way around 2015-01-15 16:16:01 +11:00
summerscope
9db1c4c708 Adding in new color variable 2015-01-15 16:15:23 +11:00
Rohan Mitchell
25a734b208 When creating enterprise, establish relationships with the owner's hubs 2015-01-15 16:08:03 +11:00
summerscope
47a8731b8e Styling for price column to distinguish between product added vs null 2015-01-15 16:01:49 +11:00
summerscope
932604bd69 Add in logic to style price column differently if nul vs has value 2015-01-15 16:01:00 +11:00
summerscope
4d7871a0bb New grey color variable 2015-01-15 16:00:21 +11:00
summerscope
51c8891fac Add animation to product title hover 2015-01-15 15:24:01 +11:00
summerscope
9b258e075b Add styling and animation to img thumbnail 2015-01-15 15:23:36 +11:00
summerscope
891a9b06a8 Add expand icon on top of image thumbnail 2015-01-15 15:23:10 +11:00
summerscope
b5879d51ac Merging master into shopfront-filters branch 2015-01-15 14:15:25 +11:00
Rohan Mitchell
dcc04ea538 On enterprise edit page, do not show side menu links we don't have permission to 2015-01-15 13:43:39 +11:00
Rohan Mitchell
83754a01ef Make side menu item visibility declarative 2015-01-15 13:43:39 +11:00
Rohan Mitchell
2d82f76a43 Fix changed var in ability spec 2015-01-15 13:43:39 +11:00
Rohan Mitchell
d5437e1508 edit_profile permission no longer shows links to manage shipping methods, payment methods and enterprise fees for an enterprise 2015-01-15 13:43:39 +11:00
Rohan Mitchell
f0bd9c1065 Fix failing specs due to addition of another enterprise 2015-01-15 13:43:39 +11:00
Rohan Mitchell
642de2f65f Only show delete enterprise link when user has permission 2015-01-15 13:43:39 +11:00
Rohan Mitchell
f6e9c9494c Enterprise user can edit profiles it has permission to 2015-01-15 13:43:39 +11:00
Rohan Mitchell
90ad2e2b7d Allow enterprises with 'edit profile' permission to edit enterprises 2015-01-15 13:43:39 +11:00
Rohan Mitchell
cfb69ae7d2 Add Permissions#editable_enterprises 2015-01-15 13:43:38 +11:00
Rohan Mitchell
a93a824b83 Admin can grant permission for an enterprise to edit the profile of another 2015-01-15 13:43:38 +11:00
Rohan Mitchell
2170c7ede1 Fix broken JS spec 2015-01-15 13:43:38 +11:00
Rob Harrington
06cf914119 Hopefully resolving order populator strangeness related to concurrency by ensuring a fresh list of line items 2015-01-15 12:10:05 +11:00
Rohan Mitchell
307cc313df Stub scope_to_hub in spec that wasn't expecting it 2015-01-13 11:46:41 +11:00
Rohan Mitchell
0431e0048c Merge branch 'master' into variant-overrides-frontend
Conflicts:
	app/controllers/shop_controller.rb
	app/views/shop/products/_form.html.haml
	spec/controllers/shop_controller_spec.rb
2015-01-12 16:48:51 +11:00
Rohan Mitchell
20bde803c8 Display overridden prices when products are in the cart 2015-01-12 14:58:35 +11:00
Rohan Mitchell
6b43354386 Restructure spec 2015-01-12 14:37:43 +11:00
Rohan Mitchell
494bb1f3b4 Fix auto-reload nerfing scope_xx_to_hub 2015-01-12 14:24:15 +11:00
Rohan Mitchell
d52b6b34e3 Spec: do not subtract stock from overrides that do not override count_on_hand 2015-01-12 11:33:53 +11:00
Rohan Mitchell
4583e29ae3 When order is placed, subtract stock from variant override 2015-01-12 11:23:53 +11:00
Rohan Mitchell
a4d4622521 Add VariantOverride.decrement_stock 2015-01-12 10:39:23 +11:00
Rohan Mitchell
20f650b472 Add VariantOverride.stock_overriden? 2015-01-12 09:32:02 +11:00
Rohan Mitchell
e013e1fe00 Don't show rspec profile by default 2015-01-09 15:30:49 +11:00
Rohan Mitchell
d40ffeef52 Remove old sidebar 2015-01-09 13:10:17 +11:00
Rohan Mitchell
6200390369 Merge branch 'lin-d-hop-add_shipping_category' 2015-01-09 12:49:09 +11:00
Rohan Mitchell
e9f32f5329 Spec that shipping category can be set when creating new products 2015-01-09 12:46:36 +11:00
Rohan Mitchell
27bc845b0b Add correct markup for tax category required asterisk 2015-01-09 12:45:35 +11:00
Rohan Mitchell
22cb8b7a71 Two-space indentation, change 'Shipping categories' to 'Shipping category' 2015-01-09 12:33:26 +11:00
Rohan Mitchell
c6db1d440c Merge branch 'add_shipping_category' of https://github.com/lin-d-hop/openfoodnetwork into lin-d-hop-add_shipping_category
Conflicts:
	app/overrides/spree/admin/products/new/replace_form.html.haml.deface
	app/views/spree/order_mailer/confirm_email.text.haml
2015-01-09 12:30:19 +11:00
Rohan Mitchell
bc448e5156 Merge branch 'lin-d-hop-report_download_namechange' 2015-01-09 11:51:46 +11:00
Rohan Mitchell
6a42f62eb2 Fix filename on order cycle management report csv, add timestamp to it and also users and enterprises report 2015-01-09 11:49:59 +11:00
Rohan Mitchell
8db09d9590 Merge branch 'report_download_namechange' of https://github.com/lin-d-hop/openfoodnetwork into lin-d-hop-report_download_namechange
Conflicts:
	app/controllers/spree/admin/reports_controller_decorator.rb
2015-01-09 11:48:23 +11:00
Rohan Mitchell
7e55262ce9 Extract most everything to private methods - neatly groups concerns together 2015-01-09 11:28:39 +11:00
Rohan Mitchell
bbc887a692 Test the exact value, not the truncated value 2015-01-09 11:26:25 +11:00
Rohan Mitchell
6f36c0463c Separate data preparation from test conditions 2015-01-09 11:26:25 +11:00
Rohan Mitchell
592ac7856a Variable naming 2015-01-09 11:26:25 +11:00
Rohan Mitchell
261dea37e9 Spec formatting 2015-01-09 11:26:25 +11:00
Rohan Mitchell
80c507cc66 Formatting 2015-01-09 11:26:25 +11:00
Lynne Davis
1ad13f0359 Cleanup of git to remove unnecessary commits from pull request 2015-01-09 11:26:24 +11:00
Rohan Mitchell
532041c07b Use Fuubar formatter for rspec - displays fails as they happen 2015-01-08 12:12:15 +11:00
Rohan Mitchell
05bd0c4168 Merge branch 'Matt-Yorkley-reports_2' 2015-01-08 10:50:27 +11:00
Rohan Mitchell
51b0d7e0eb Move private method to helper 2015-01-08 10:48:02 +11:00
Rohan Mitchell
d2e0d4f44a Fix grammar 2015-01-08 10:39:51 +11:00
Rohan Mitchell
ab26902e4e Move money decorator to lib dir, as it's a decorator for a lib class, not a model 2015-01-08 10:39:14 +11:00
Rohan Mitchell
6adb4194c2 Extract date range form to partial 2015-01-08 10:31:51 +11:00
Rohan Mitchell
b6f29c778e Use haml syntax for defining divs 2015-01-08 10:23:37 +11:00
Rohan Mitchell
4839c00d62 Retrieve currency_symbol via private method rather than before_filter + instance var - cleaner syntax 2015-01-08 10:12:32 +11:00
Rohan Mitchell
a438216189 Merge branch 'reports_2' of https://github.com/Matt-Yorkley/openfoodnetwork into Matt-Yorkley-reports_2
Conflicts:
	app/controllers/spree/admin/reports_controller_decorator.rb
2015-01-08 10:08:12 +11:00
Rohan Mitchell
29f9b3bbd7 Merge branch 'Matt-Yorkley-tax_cat_dropdown' 2015-01-08 09:51:27 +11:00
Rohan Mitchell
ac59665e3c Test validations without creating models in database 2015-01-08 09:48:33 +11:00
Rohan Mitchell
e4efda2f96 Move model spec into validations block 2015-01-08 09:37:35 +11:00
Rohan Mitchell
a9b91bc52a Tighten spec: setting tax category should succeed 2015-01-08 09:35:18 +11:00
Rohan Mitchell
f90ee33c89 Use the tax category factory provided by Spree 2015-01-08 09:27:29 +11:00
Rohan Mitchell
087ccb52f9 Merge branch 'tax_cat_dropdown' of https://github.com/Matt-Yorkley/openfoodnetwork into Matt-Yorkley-tax_cat_dropdown 2015-01-08 09:09:20 +11:00
Rohan Mitchell
4bf8716786 Extract complete_checkout to method 2015-01-07 16:29:15 +11:00
Rohan Mitchell
c0030ddb13 use_short_wait can now take a flexible wait time 2015-01-07 16:28:03 +11:00
Rohan Mitchell
370133b875 Fix minor spec issues 2015-01-07 16:06:23 +11:00
summerscope
6863dd75ef Restyling button for price breakdown to make it more clear that users press again to close the pop over 2014-12-19 17:05:13 +11:00
summerscope
fafdb29fcb Regenerated icon font, smaller file size and updated graph icon 2014-12-19 17:04:26 +11:00
Rohan Mitchell
85882a73ff Merge branch 'lin-d-hop-266reportsbranch' 2014-12-19 16:51:38 +11:00
Rohan Mitchell
2bad590ef4 Order confirmation and order objects use overridden prices 2014-12-19 16:51:11 +11:00
Rohan Mitchell
c3995ee4d5 Checkout shows overridden prices 2014-12-19 16:51:11 +11:00
Rohan Mitchell
94684e9963 Show overridden price in shopping cart 2014-12-19 16:51:11 +11:00
Rohan Mitchell
1e1a070b2b Scope Variant#price_in 2014-12-19 16:51:10 +11:00
summerscope
d50f8dcd01 Tweak styling shopfront page to allow for new icons and hover state 2014-12-19 14:53:46 +11:00
summerscope
813ef463a2 Tweak markup shopfront page to add icon 2014-12-19 14:53:25 +11:00
Rohan Mitchell
72118f4e2e Fix syntax error, spec for removed column 2014-12-19 10:01:46 +11:00
Rohan Mitchell
e9f04c3c15 Clean up whitespace 2014-12-19 10:01:21 +11:00
Rohan Mitchell
6e0576235d Use create\! instead of build - more concise, raises exception on error 2014-12-19 09:51:32 +11:00
Rohan Mitchell
27d646c0e8 Tweak indentation, remove some blank lines 2014-12-19 09:51:32 +11:00
Rohan Mitchell
0151ecbb32 Add additional rows to payment method selection 2014-12-19 09:51:32 +11:00
Rohan Mitchell
d548515684 Remove unused header column 2014-12-19 09:51:13 +11:00
Rohan Mitchell
343af1f1e0 Rename report_shipping_options to report_shipping_method_options for symmetry with report_payment_method_options 2014-12-19 09:51:07 +11:00
Rohan Mitchell
3b58d99abc Fix spec failure 2014-12-19 09:51:02 +11:00
Rohan Mitchell
4a30f27b3d Merge branch '266reportsbranch' of https://github.com/lin-d-hop/openfoodnetwork into lin-d-hop-266reportsbranch
Conflicts:
	app/controllers/spree/admin/reports_controller_decorator.rb
	spec/models/spree/order_spec.rb
2014-12-19 09:38:02 +11:00
Rohan Mitchell
c4b45bdbbf Fix line items returning prices with fractional cents 2014-12-18 16:24:59 +11:00
Rohan Mitchell
b0f5d0170c Spec that overridden price with fees appears in quick cart 2014-12-18 13:32:28 +11:00
Rohan Mitchell
5fcb2982fa Fees are calculated correctly for items with variant overrides 2014-12-18 11:53:17 +11:00
Rohan Mitchell
ead84aa9ff Add ids to product listing products and variants 2014-12-18 11:00:45 +11:00
Rohan Mitchell
1d3800696e Variant overrides can override stock levels 2014-12-18 10:46:47 +11:00
Rohan Mitchell
f5ee9ba2f3 VariantOverride looks up count_on_hand 2014-12-18 10:21:07 +11:00
Rohan Mitchell
e6eecd3ae2 Replace proxies with modules 2014-12-18 10:20:31 +11:00
Rohan Mitchell
0832a8f63d Viewing products shows overridden prices 2014-12-17 16:00:25 +11:00
Rohan Mitchell
23c7715929 Cosmetic change 2014-12-17 14:03:54 +11:00
Rohan Mitchell
2ea7bdbec6 Move controller spec to serializer spec 2014-12-17 14:01:59 +11:00
Rohan Mitchell
6c300431d2 Move Product#variants_for to Variant.for_distribution scope 2014-12-17 13:42:30 +11:00
Rohan Mitchell
91c500417b Swap param order 2014-12-17 08:55:27 +11:00
Lynne Davis
7e49bd634e Updated the specs with Rohans suggestions 2014-12-12 18:23:43 +00:00
Lynne Davis
eeae72352b Renamed methods and vars to better fit naming conventions 2014-12-12 10:11:33 +00:00
Lynne Davis
079781576b Adding new specs and a couple updates the lib/report 2014-12-11 12:47:56 +00:00
Lynne Davis
f878e18037 Update that works better with the specs 2014-12-08 16:25:18 +00:00
Lynne Davis
633a8a49e2 updating spec based on the wise advice of Rohan 2014-12-03 00:35:53 +00:00
Lynne Davis
a5ae1c490c Fixing typo in report found through testing 2014-12-02 17:48:04 +00:00
Lynne Davis
c2c51a5531 Fixing typo in feature spec 2014-12-02 12:24:34 +00:00
Lynne Davis
35c27bf516 First specs for additional scope to order model. Not liking the repeated code so would appreciate feedback to get rid of it. Thanks! 2014-11-27 20:36:41 +00:00
Matt-Yorkley
e4d1ae7548 Refactored currency symbol display 2014-11-24 18:20:10 +00:00
Matt-Yorkley
4f153714a8 Reports pages improvements and i18n 2014-11-23 17:26:26 +00:00
Matt-Yorkley
451dd3966f form partial 2014-11-23 15:22:56 +00:00
Matt-Yorkley
c3829ae64f Tax category dropdown on create product form 2014-11-23 15:18:16 +00:00
Lynne Davis
b81bf60dc2 267: Cont. Didn't realise commit -a doesn't add a file 2014-11-18 19:30:44 +00:00
Lynne Davis
cc0da142b7 267: Adding to new product form ability to add shipping category to record frozen/chilled 2014-11-18 19:28:49 +00:00
Lynne Davis
03b59eae75 266: Updating with rohans suggestions to tidy up and 'rubify' the code. Thanks for the tips Rohan! 2014-11-14 15:56:07 +00:00
Lynne Davis
e89184de02 286: Last sneaky dollar sign. Updated to use spree_number_to_currency 2014-11-14 14:24:22 +00:00
Lynne Davis
cc3959467d 285: Report downlaod naming - Updating to the cleaner suggestions of Rohan. Note to self, don't be lazy :-) 2014-11-13 10:30:00 +00:00
Lynne Davis
15f29f4c8e 266: Adding ability to search by distribution 2014-11-12 18:52:25 +00:00
Lynne Davis
932d571d2c 266: Updating to incorporate Rohans suggestions. Searching on payment method name rather than id 2014-11-12 11:47:26 +00:00
Lynne Davis
9a5ee81431 Changing report download titles in include download date 2014-11-11 17:49:08 +00:00
Lynne Davis
6f6ae309c6 266 UK: Adding first UK report - Payment Methods Report - to find balances per ordercycle for multiple payment method options. Working, but not complete to spec yet 2014-11-02 11:26:39 +00:00
160 changed files with 2230 additions and 957 deletions

2
.rspec
View File

@@ -1,2 +1,2 @@
--colour
--profile
--format Fuubar

View File

@@ -21,7 +21,7 @@ gem 'comfortable_mexican_sofa'
gem 'simple_form', :github => 'RohanM/simple_form'
gem 'unicorn'
gem 'angularjs-rails'
gem 'angularjs-rails', '1.2.13'
gem 'bugsnag'
gem 'newrelic_rpm'
gem 'haml'
@@ -78,6 +78,7 @@ gem 'jquery-rails'
group :test, :development do
# Pretty printed test output
gem 'turn', '~> 0.8.3', :require => false
gem 'fuubar'
gem 'rspec-rails'
gem 'shoulda-matchers'
gem 'factory_girl_rails', :require => false

View File

@@ -269,6 +269,9 @@ GEM
railties (>= 3.1.0)
sass (>= 3.2.0)
fssm (0.2.10)
fuubar (1.3.3)
rspec (>= 2.14.0, < 3.1.0)
ruby-progressbar (~> 1.4)
geocoder (1.1.8)
gmaps4rails (1.5.6)
guard (2.2.4)
@@ -449,6 +452,7 @@ GEM
rspec-expectations (~> 2.14.0)
rspec-mocks (~> 2.14.0)
ruby-hmac (0.4.0)
ruby-progressbar (1.7.1)
safe_yaml (0.9.5)
sass (3.2.19)
sass-rails (3.2.6)
@@ -528,7 +532,7 @@ DEPENDENCIES
andand
angular-rails-templates
angularjs-file-upload-rails (~> 1.1.0)
angularjs-rails
angularjs-rails (= 1.2.13)
awesome_print
aws-sdk
bugsnag
@@ -548,6 +552,7 @@ DEPENDENCIES
foundation-icons-sass-rails
foundation-rails
foundation_rails_helper!
fuubar
geocoder
gmaps4rails
guard

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

View File

@@ -0,0 +1,55 @@
<!-- By Sam Herbert (@sherb), for everyone. More @ http://goo.gl/7AJzbL -->
<svg width="58" height="58" viewBox="0 0 58 58" xmlns="http://www.w3.org/2000/svg">
<g fill="none" fill-rule="evenodd">
<g transform="translate(2 1)" stroke="#0096ad" stroke-width="1.5">
<circle cx="42.601" cy="11.462" r="5" fill-opacity="1" fill="#0096ad">
<animate attributeName="fill-opacity"
begin="0s" dur="1.3s"
values="1;0;0;0;0;0;0;0" calcMode="linear"
repeatCount="indefinite" />
</circle>
<circle cx="49.063" cy="27.063" r="5" fill-opacity="0" fill="#0096ad">
<animate attributeName="fill-opacity"
begin="0s" dur="1.3s"
values="0;1;0;0;0;0;0;0" calcMode="linear"
repeatCount="indefinite" />
</circle>
<circle cx="42.601" cy="42.663" r="5" fill-opacity="0" fill="#0096ad">
<animate attributeName="fill-opacity"
begin="0s" dur="1.3s"
values="0;0;1;0;0;0;0;0" calcMode="linear"
repeatCount="indefinite" />
</circle>
<circle cx="27" cy="49.125" r="5" fill-opacity="0" fill="#0096ad">
<animate attributeName="fill-opacity"
begin="0s" dur="1.3s"
values="0;0;0;1;0;0;0;0" calcMode="linear"
repeatCount="indefinite" />
</circle>
<circle cx="11.399" cy="42.663" r="5" fill-opacity="0" fill="#0096ad">
<animate attributeName="fill-opacity"
begin="0s" dur="1.3s"
values="0;0;0;0;1;0;0;0" calcMode="linear"
repeatCount="indefinite" />
</circle>
<circle cx="4.938" cy="27.063" r="5" fill-opacity="0" fill="#0096ad">
<animate attributeName="fill-opacity"
begin="0s" dur="1.3s"
values="0;0;0;0;0;1;0;0" calcMode="linear"
repeatCount="indefinite" />
</circle>
<circle cx="11.399" cy="11.462" r="5" fill-opacity="0" fill="#0096ad">
<animate attributeName="fill-opacity"
begin="0s" dur="1.3s"
values="0;0;0;0;0;0;1;0" calcMode="linear"
repeatCount="indefinite" />
</circle>
<circle cx="27" cy="5" r="5" fill-opacity="0" fill="#0096ad">
<animate attributeName="fill-opacity"
begin="0s" dur="1.3s"
values="0;0;0;0;0;0;0;1" calcMode="linear"
repeatCount="indefinite" />
</circle>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@@ -1,68 +1,19 @@
angular.module("admin.enterprises")
.controller "enterpriseCtrl", ($scope, NavigationCheck, Enterprise, PaymentMethods, ShippingMethods, SideMenu) ->
.controller "enterpriseCtrl", ($scope, NavigationCheck, Enterprise, EnterprisePaymentMethods, EnterpriseShippingMethods, SideMenu) ->
$scope.Enterprise = Enterprise.enterprise
$scope.PaymentMethods = PaymentMethods.paymentMethods
$scope.ShippingMethods = ShippingMethods.shippingMethods
console.log Enterprise
$scope.PaymentMethods = EnterprisePaymentMethods.paymentMethods
$scope.ShippingMethods = EnterpriseShippingMethods.shippingMethods
$scope.navClear = NavigationCheck.clear
# htmlVariable is used by textAngular wysiwyg for the long descrtiption.
$scope.pristineEmail = $scope.Enterprise.email
$scope.menu = SideMenu
# Provide a callback for generating warning messages displayed before leaving the page. This is passed in
# from a directive "nav-check" in the page - if we pass it here it will be called in the test suite,
# and on all new uses of this contoller, and we might not want that .
$scope.enterpriseNavCallback = ->
if $scope.enterprise.$dirty
enterpriseNavCallback = ->
if $scope.Enterprise.$dirty
"Your changes to the enterprise are not saved yet."
for payment_method in $scope.PaymentMethods
payment_method.selected = payment_method.id in $scope.Enterprise.payment_method_ids
$scope.paymentMethodsColor = ->
if $scope.PaymentMethods.length > 0
if $scope.selectedPaymentMethodsCount() > 0 then "blue" else "red"
else
"red"
$scope.selectedPaymentMethodsCount = ->
$scope.PaymentMethods.reduce (count, payment_method) ->
count++ if payment_method.selected
count
, 0
for shipping_method in $scope.ShippingMethods
shipping_method.selected = shipping_method.id in $scope.Enterprise.shipping_method_ids
$scope.shippingMethodsColor = ->
if $scope.ShippingMethods.length > 0
if $scope.selectedShippingMethodsCount() > 0 then "blue" else "red"
else
"red"
$scope.selectedShippingMethodsCount = ->
$scope.ShippingMethods.reduce (count, shipping_method) ->
count++ if shipping_method.selected
count
, 0
$scope.$watch "Enterprise.is_primary_producer", (newValue, oldValue) ->
if !newValue && $scope.Enterprise.sells == "none"
$scope.menu.hide_item_by_name('Enterprise Fees')
else
$scope.menu.show_item_by_name('Enterprise Fees')
$scope.$watch "Enterprise.sells", (newValue, oldValue) ->
if newValue == "none"
$scope.menu.hide_item_by_name('Shipping Methods')
$scope.menu.hide_item_by_name('Payment Methods')
$scope.menu.hide_item_by_name('Shop Preferences')
if $scope.Enterprise.is_primary_producer
$scope.menu.show_item_by_name('Enterprise Fees')
else
$scope.menu.hide_item_by_name('Enterprise Fees')
else
$scope.menu.show_item_by_name('Shipping Methods')
$scope.menu.show_item_by_name('Payment Methods')
$scope.menu.show_item_by_name('Shop Preferences')
$scope.menu.show_item_by_name('Enterprise Fees')
# Register the NavigationCheck callback
NavigationCheck.register(enterpriseNavCallback)

View File

@@ -0,0 +1,23 @@
angular.module("admin.enterprises")
.controller "permalinkCtrl", ($scope, PermalinkChecker) ->
# locals
initialPermalink = $scope.Enterprise.permalink
pendingRequest = null
# variables on $scope
$scope.availablility = ""
$scope.checking = false
$scope.$watch "Enterprise.permalink", (newValue, oldValue) ->
$scope.checking = true
pendingRequest = PermalinkChecker.check(newValue)
pendingRequest.then (data) ->
if data.permalink == initialPermalink
$scope.availability = ""
else
$scope.availability = data.available
$scope.Enterprise.permalink = data.permalink
$scope.checking = false
, (data) ->
# Do nothing (this is hopefully an aborted request)

View File

@@ -1,5 +1,5 @@
angular.module("admin.enterprises")
.controller "sideMenuCtrl", ($scope, Enterprise, SideMenu) ->
.controller "sideMenuCtrl", ($scope, $parse, Enterprise, SideMenu, enterprisePermissions) ->
$scope.Enterprise = Enterprise.enterprise
$scope.menu = SideMenu
$scope.select = SideMenu.select
@@ -12,10 +12,30 @@ angular.module("admin.enterprises")
{ name: 'About', icon_class: "icon-pencil" }
{ name: 'Business Details', icon_class: "icon-briefcase" }
{ name: 'Images', icon_class: "icon-picture" }
{ name: "Shipping Methods", icon_class: "icon-truck" }
{ name: "Payment Methods", icon_class: "icon-money" }
{ name: "Enterprise Fees", icon_class: "icon-tasks" }
{ name: "Shop Preferences", icon_class: "icon-shopping-cart" }
{ name: "Shipping Methods", icon_class: "icon-truck", show: "showShippingMethods()" }
{ name: "Payment Methods", icon_class: "icon-money", show: "showPaymentMethods()" }
{ name: "Enterprise Fees", icon_class: "icon-tasks", show: "showEnterpriseFees()" }
{ name: "Shop Preferences", icon_class: "icon-shopping-cart", show: "showShopPreferences()" }
]
$scope.select(0)
$scope.showItem = (item) ->
if item.show?
$parse(item.show)($scope)
else
true
$scope.showShippingMethods = ->
enterprisePermissions.can_manage_shipping_methods && $scope.Enterprise.sells != "none"
$scope.showPaymentMethods = ->
enterprisePermissions.can_manage_payment_methods && $scope.Enterprise.sells != "none"
$scope.showEnterpriseFees = ->
enterprisePermissions.can_manage_enterprise_fees && ($scope.Enterprise.sells != "none" || $scope.Enterprise.is_primary_producer)
$scope.showShopPreferences = ->
$scope.Enterprise.sells != "none"

View File

@@ -0,0 +1,20 @@
angular.module("admin.enterprises")
.factory "EnterprisePaymentMethods", (Enterprise, PaymentMethods) ->
new class EnterprisePaymentMethods
paymentMethods: PaymentMethods.paymentMethods
constructor: ->
for payment_method in @paymentMethods
payment_method.selected = payment_method.id in Enterprise.enterprise.payment_method_ids
displayColor: ->
if @paymentMethods.length > 0 && @selectedCount() > 0
"blue"
else
"red"
selectedCount: ->
@paymentMethods.reduce (count, payment_method) ->
count++ if payment_method.selected
count
, 0

View File

@@ -0,0 +1,20 @@
angular.module("admin.enterprises")
.factory "EnterpriseShippingMethods", (Enterprise, ShippingMethods) ->
new class EnterpriseShippingMethods
shippingMethods: ShippingMethods.shippingMethods
constructor: ->
for shipping_method in @shippingMethods
shipping_method.selected = shipping_method.id in Enterprise.enterprise.shipping_method_ids
displayColor: ->
if @shippingMethods.length > 0 && @selectedCount() > 0
"blue"
else
"red"
selectedCount: ->
@shippingMethods.reduce (count, shipping_method) ->
count++ if shipping_method.selected
count
, 0

View File

@@ -0,0 +1,36 @@
angular.module("admin.enterprises").factory 'PermalinkChecker', ($q, $http) ->
new class PermalinkChecker
deferredRequest: null
deferredAbort: null
check: (permalink) =>
@abort(@deferredAbort) if @deferredRequest && @deferredRequest.promise
@deferredRequest = deferredRequest = $q.defer()
@deferredAbort = deferredAbort = $q.defer()
request = $http(
method: "GET"
url: "/enterprises/check_permalink?permalink=#{permalink}"
headers:
Accept: 'application/javascript'
timeout: deferredAbort.promise
)
.success( (data) =>
deferredRequest.resolve
permalink: data
available: "Available"
).error (data,status) =>
if status == 409
deferredRequest.resolve
permalink: data
available: "Unavailable"
else
# Something went wrong or request was aborted
deferredRequest.reject()
deferredRequest.promise.finally ->
request = deferredRequest.promise = null;
deferredRequest.promise
abort: (deferredAbort) ->
deferredAbort.resolve()

View File

@@ -74,7 +74,8 @@ angular.module('admin.order_cycles', ['ngResource'])
$scope.removeDistributionOfVariant = (variant_id) ->
OrderCycle.removeDistributionOfVariant(variant_id)
$scope.submit = ->
$scope.submit = (event) ->
event.preventDefault()
OrderCycle.create()
])
@@ -154,7 +155,8 @@ angular.module('admin.order_cycles', ['ngResource'])
$scope.removeDistributionOfVariant = (variant_id) ->
OrderCycle.removeDistributionOfVariant(variant_id)
$scope.submit = ->
$scope.submit = (event) ->
event.preventDefault()
OrderCycle.update()
])

View File

@@ -38,6 +38,7 @@ angular.module('admin.order_cycles').controller "AdminSimpleCreateOrderCycleCtrl
$scope.enterpriseFeesForEnterprise = (enterprise_id) ->
EnterpriseFee.forEnterprise(parseInt(enterprise_id))
$scope.submit = ->
$scope.submit = (event) ->
event.preventDefault()
OrderCycle.mirrorIncomingToOutgoingProducts()
OrderCycle.create()

View File

@@ -32,6 +32,7 @@ angular.module('admin.order_cycles').controller "AdminSimpleEditOrderCycleCtrl",
$event.preventDefault()
OrderCycle.removeCoordinatorFee(index)
$scope.submit = ->
$scope.submit = (event) ->
event.preventDefault()
OrderCycle.mirrorIncomingToOutgoingProducts()
OrderCycle.update()

View File

@@ -87,20 +87,21 @@ angular.module('admin.order_cycles').factory('OrderCycle', ($resource, $window)
load: (order_cycle_id, callback=null) ->
service = this
OrderCycle.get {order_cycle_id: order_cycle_id}, (oc) ->
angular.extend(service.order_cycle, oc)
service.order_cycle.incoming_exchanges = []
service.order_cycle.outgoing_exchanges = []
for exchange in service.order_cycle.exchanges
if exchange.incoming
angular.extend(exchange, {enterprise_id: exchange.sender_id, active: true})
delete(exchange.receiver_id)
service.order_cycle.incoming_exchanges.push(exchange)
else
angular.extend(exchange, {enterprise_id: exchange.receiver_id, active: true})
delete(exchange.sender_id)
service.order_cycle.outgoing_exchanges.push(exchange)
delete oc.$promise
delete oc.$resolved
angular.extend(service.order_cycle, oc)
service.order_cycle.incoming_exchanges = []
service.order_cycle.outgoing_exchanges = []
for exchange in service.order_cycle.exchanges
if exchange.incoming
angular.extend(exchange, {enterprise_id: exchange.sender_id, active: true})
delete(exchange.receiver_id)
service.order_cycle.incoming_exchanges.push(exchange)
else
angular.extend(exchange, {enterprise_id: exchange.receiver_id, active: true})
delete(exchange.sender_id)
service.order_cycle.outgoing_exchanges.push(exchange)
delete(service.order_cycle.exchanges)
service.loaded = true

View File

@@ -2,7 +2,7 @@ angular.module("admin.payment_methods")
.factory "PaymentMethods", (paymentMethods) ->
new class PaymentMethods
paymentMethods: paymentMethods
findByID: (id) ->
for paymentMethod in @paymentMethods
return paymentMethod if paymentMethod.id is id

View File

@@ -4,6 +4,7 @@ angular.module("ofn.admin").factory 'EnterpriseRelationships', ($http, enterpris
all_permissions: [
'add_to_order_cycle'
'manage_products'
'edit_profile'
]
constructor: ->
@@ -26,3 +27,4 @@ angular.module("ofn.admin").factory 'EnterpriseRelationships', ($http, enterpris
switch permission
when "add_to_order_cycle" then "to add to order cycle"
when "manage_products" then "to manage products"
when "edit_profile" then "to edit profile"

View File

@@ -2,7 +2,7 @@ angular.module("admin.shipping_methods")
.factory "ShippingMethods", (shippingMethods) ->
new class ShippingMethods
shippingMethods: shippingMethods
findByID: (id) ->
for shippingMethod in @shippingMethods
return shippingMethod if shippingMethod.id is id

View File

@@ -13,7 +13,7 @@ angular.module("admin.taxons").factory "Taxons", (taxons, $filter) ->
# For finding multiple Taxons represented by comma delimited string
findByIDs: (ids) ->
@taxonsByID[taxon_id] for taxon_id in ids.split(",")
@taxonsByID[taxon_id] for taxon_id in ids.split(",") when @taxonsByID[taxon_id]
findByTerm: (term) ->
$filter('filter')(@taxons, term)

View File

@@ -1,10 +0,0 @@
angular.module("admin.utils").directive "navCheckCallback", (NavigationCheck)->
restrict: 'A'
scope:
navCheckCallback: '&'
link: (scope,element,attributes) ->
# Provide a callback, otherwise this default will be used:
callback = scope.navCheckCallback()
callback ||= ->
"You will lose any unsaved work!"
NavigationCheck.register(callback)

View File

@@ -4,7 +4,7 @@ Darkswarm.controller "CheckoutCtrl", ($scope, storage, Checkout, CurrentUser, Cu
# Bind to local storage
$scope.fieldsToBind = ["bill_address", "email", "payment_method_id", "shipping_method_id", "ship_address"]
prefix = "order_#{Checkout.order.id}#{CurrentUser?.id}#{CurrentHub.hub.id}"
prefix = "order_#{Checkout.order.id}#{CurrentUser.id or ""}#{CurrentHub.hub.id}"
for field in $scope.fieldsToBind
storage.bind $scope, "Checkout.order.#{field}",
@@ -16,7 +16,7 @@ Darkswarm.controller "CheckoutCtrl", ($scope, storage, Checkout, CurrentUser, Cu
$scope.order = Checkout.order # Ordering is important
$scope.secrets = Checkout.secrets
$scope.enabled = !!CurrentUser
$scope.enabled = !!CurrentUser.id?
$scope.purchase = (event, form) ->
event.preventDefault()

View File

@@ -43,6 +43,11 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http)->
@line_items.filter (li)->
li.quantity > 0
total_item_count: =>
@line_items_present().reduce (sum,li) ->
sum = sum + li.quantity
, 0
empty: =>
@line_items_present().length == 0
@@ -62,4 +67,4 @@ Darkswarm.factory 'Cart', (CurrentOrder, Variants, $timeout, $http)->
variant: variant
quantity: null
max_quantity: null
@line_items.push variant.line_item
@line_items.push variant.line_item

View File

@@ -1,7 +1,4 @@
Darkswarm.factory 'CurrentUser', (user)-> # This is for the current user
if user and !$.isEmptyObject(user)
new class CurrentUser
constructor: ->
@[k] = v for k, v of user
else
undefined
new class CurrentUser
constructor: ->
@[k] = v for k, v of user if user and !$.isEmptyObject(user)

View File

@@ -1,9 +1,14 @@
Darkswarm.factory 'HashNavigation', ($location) ->
new class HashNavigation
hash: null
hash: null
constructor: ->
# Make sure we have a path as hashes
# dont seem to work so well without them
$location.path("") if !$location.path()
active: (hash)->
$location.hash() == hash
$location.hash() == hash
navigate: (hash)->
@hash = hash

View File

@@ -12,22 +12,22 @@
%li.cost
.right {{ variant.price | localizeCurrency }}
Item cost
%li{"bo-if" => "variant.fees.admin"}
%li.admin-fee{"bo-if" => "variant.fees.admin"}
.right {{ variant.fees.admin | localizeCurrency }}
Admin fee
%li{"bo-if" => "variant.fees.sales"}
%li.sales-fee{"bo-if" => "variant.fees.sales"}
.right {{ variant.fees.sales | localizeCurrency }}
Sales fee
%li{"bo-if" => "variant.fees.packing"}
%li.packing-fee{"bo-if" => "variant.fees.packing"}
.right {{ variant.fees.packing | localizeCurrency }}
Packing fee
%li{"bo-if" => "variant.fees.transport"}
%li.transport-fee{"bo-if" => "variant.fees.transport"}
.right {{ variant.fees.transport | localizeCurrency }}
Transport fee
%li{"bo-if" => "variant.fees.fundraising"}
%li.fundraising-fee{"bo-if" => "variant.fees.fundraising"}
.right {{ variant.fees.fundraising | localizeCurrency }}
Fundraising fee
%li
%li.total
%strong
.right = {{ variant.price_with_fees | localizeCurrency }}
&nbsp;

View File

@@ -1,2 +1,2 @@
%button.graph-button{"ng-class" => "{open: tt_isOpen}"}
%i.ofn-i_058-graph
/ %i.ofn-i_058-graph

View File

@@ -40,6 +40,6 @@
.message{ ng: { hide: "imageSrc() || imageUploader.isUploading" } }
Your logo will appear here for review once uploaded
.loading{ ng: { hide: "!imageUploader.isUploading" } }
%img.spinner{ src: "/assets/loading.gif" }
%img.spinner{ src: "/assets/spinning-circles.svg" }
%br/
Uploading...

View File

@@ -38,6 +38,6 @@
.message{ ng: { hide: "imageSrc() || imageUploader.isUploading" } }
Your logo will appear here for review once uploaded
.loading{ ng: { hide: "!imageUploader.isUploading" } }
%img.spinner{ src: "/assets/loading.gif" }
%img.spinner{ src: "/assets/spinning-circles.svg" }
%br/
Uploading...

View File

@@ -58,5 +58,5 @@
.small-12.medium-2.large-2.columns.total-price.text-right
.table-cell
%strong
%strong{"ng-class" => "{filled: variant.totalPrice()}"}
{{ variant.totalPrice() | localizeCurrency }}

View File

@@ -0,0 +1,14 @@
span.unavailable, span.available {
font-weight: bold;
i {
font-size: 150%;
}
}
span.available {
color: #9fc820;
}
span.unavailable {
color: #DA5354;
}

View File

@@ -77,44 +77,36 @@ ordercycle
button.graph-button
z-index: 9999999
border: 1px solid transparent
@include box-shadow(none)
padding: 0
margin: 0
@include border-radius(999rem)
display: inline
background-color: rgba(255,255,255,0.5)
padding: 5px
@media all and (max-width: 768px)
display: none
// Hide for small
&:hover, &:active, &:focus
background-color: rgba(255,255,255,1)
i.ofn-i_058-graph
color: $clr-brick-bright
i.ofn-i_058-graph
padding: 4px
@include box-shadow(none)
@include border-radius(999rem)
&:before
@include icon-font
content: '\e639'
color: #999
margin: 0
padding: 0
font-size: 1rem
@media all and (max-width: 640px)
padding: 3px
i.ofn-i_058-graph
font-size: 0.75rem
&:focus
border: 1px solid #e0e0e0
background-color: rgba(255,255,255,1)
&:before
color: #666
&:hover, &:active
background-color: rgba(255,255,255,1)
border: 1px solid transparent
&:before
color: $clr-brick-bright
@media all and (max-width: 768px)
// Hide for small
display: none
button.graph-button.open
@include box-shadow(inset 0 1px 1px 0 rgba(0,0,0,0.35))
border: 1px solid #999
&:hover, &:active, &:focus
background-color: rgba(255,255,255,1)
i.ofn-i_058-graph
color: $clr-brick-bright
i.ofn-i_058-graph
color: $clr-brick
border: 1px solid transparent
background-color: $clr-brick-bright
&:before
content: '\e608'
color: white

View File

@@ -1,4 +1,5 @@
@import branding.css.sass
@import animations.sass
.darkswarm
products
@@ -71,9 +72,14 @@
// Total price
.total-price
padding-left: 0rem
color: $disabled-med
.filled
color: $med-drk-grey
@media all and (max-width: 640px)
background: #777
color: white
color: $disabled-med
.filled
color: white
.table-cell
height: 27px
@@ -97,17 +103,19 @@
@media all and (max-width: 768px)
padding-left: 4.9375rem
@media all and (max-width: 640px)
padding-left: 4.5rem
@media all and (max-width:480px)
padding-left: 0.9375rem
small
font-size: 80%
h3
font-size: 1.5rem
margin: 0
h3 a
color: #222
i
@include csstrans
font-size: 0.6em
&:hover, &:focus, &:active
color: black
color: $clr-brick
i
font-size: 0.8em

View File

@@ -1,26 +1,59 @@
@import branding
@import animations.sass
.darkswarm
products
product
.product-thumb
@include csstrans
position: absolute
top: 3px
top: 2px
left: 0px
width: 7rem
height: 7rem
outline: 1px solid $disabled-bright
float: left
display: block
z-index: 999999
background-color: white
overflow: hidden
i
@include csstrans
transition-delay: 150ms
position: absolute
left: 45%
top: 45%
z-index: 99999
color: white
font-size: 1rem
opacity: 0
img
@include csstrans
opacity: 1
@include transform-scale(scale(1))
&:hover, &:focus, &:active
background-color: $clr-brick
i
left: 32%
top: 30%
font-size: 3rem
opacity: 1
img
opacity: 0.5
@include transform-scale(scale(1.1))
@media all and (max-width: 768px)
top: 2px
width: 4rem
height: 4rem
@media all and (max-width: 480px)
&:hover, &:focus, &:active
i
left: 30%
top: 30%
font-size: 2rem
@media all and (max-width: 640px)
display: none
width: 0rem
height: 0rem
height: 0rem

View File

@@ -9,9 +9,10 @@
margin-top: -1.1rem
padding-top: 0.25rem
z-index: 999999
@media all and (max-width: 768px)
margin-top: -0.85rem
@media all and (max-width: 480px)
background-size: 28px 32px
min-height: 32px
width: 28px
render-svg
svg
@@ -19,3 +20,12 @@
height: 24px
path
fill: #999
@media all and (max-width: 768px)
margin-top: -0.85rem
@media all and (max-width: 480px)
render-svg
svg
width: 18px
height: 18px

View File

@@ -66,10 +66,8 @@ products .filter-box
table-layout: fixed
text-transform: capitalize
overflow: visible
// width: 100%
// height: 2rem
line-height: 1
color: #444
color: $med-drk-grey
font-size: 0.875rem
span
display: table-cell

View File

@@ -51,6 +51,21 @@
100%
opacity: 1
@-webkit-keyframes spin
0%
-webkit-transform: rotate(0deg)
transform: rotate(0deg)
100%
-webkit-transform: rotate(359deg)
transform: rotate(359deg)
@keyframes spin
0%
-webkit-transform: rotate(0deg)
transform: rotate(0deg)
100%
-webkit-transform: rotate(359deg)
transform: rotate(359deg)
// ANIMATION CLASSES
.fade

View File

@@ -21,5 +21,6 @@ $disabled-med: #b3b3b3
$disabled-dark: #999
$disabled-v-dark: #808080
$med-grey: #666
$med-drk-grey: #444
$dark-grey: #333
$black: #000

View File

@@ -3,12 +3,10 @@
@import branding
.product-img
border-bottom: 40px white solid
border-top: 20px white solid
border-left: 20px white solid
border-right: 20px white solid
padding: 5px
margin-bottom: 10px
outline: 1px solid #ccc
@include box-shadow(0 1px 2px 1px rgba(0,0,0,0.25))
@include box-shadow(0 1px 2px 1px rgba(0,0,0,0.15))
.hero-img
outline: 1px solid $disabled-bright

View File

@@ -8,9 +8,10 @@
nav
@include textpress
.joyride-tip-guide .button
text-shadow: none
// Default overrides - big menu
.top-bar-section ul li.ofn-logo > a
display: table-cell
vertical-align: middle

View File

@@ -1,4 +1,5 @@
@import mixins
@import animations
@import variables
@import branding
@import big-input
@@ -25,6 +26,21 @@
.add_to_cart
margin-top: 2rem
form
input.small.button.primary.right.add_to_cart
&.dirty
padding-left: 3.2rem
i.cart-spinner
position: absolute
top: 14px
right: 146px
color: white
font-size: 1.2em
// Necessary to be below Z index of cart popover:
z-index: 98
-webkit-animation: spin 2s infinite linear
animation: spin 2s infinite linear
product
@include csstrans
border-bottom: 1px solid #e5e5e5
@@ -33,7 +49,7 @@
margin-bottom: 20px !important
position: relative
display: block
color: #444
color: $med-drk-grey
&:hover, &:focus, &:active
border-bottom: 1px solid $clr-brick-med-bright
@@ -62,12 +78,14 @@
@media all and (max-width: 640px)
padding-right: 0.25rem
i.ofn-i_056-bulk, i.ofn-i_036-producers
i.ofn-i_056-bulk
font-size: 1rem
padding-right: 0rem
i.ofn-i_036-producers
padding-left: 0.5rem
padding-left: 0.2rem
padding-right: 0rem
font-size: 0.8rem
.shopfront_message, .shopfront_closed_message
padding: 15px

View File

@@ -1,7 +1,7 @@
module Admin
class EnterprisesController < ResourceController
before_filter :load_enterprise_set, :only => :index
before_filter :load_countries, :except => :index
before_filter :load_countries, :except => [:index, :set_sells, :check_permalink]
before_filter :load_methods_and_fees, :only => [:new, :edit, :update, :create]
before_filter :load_taxons, :only => [:new, :edit, :update, :create]
before_filter :check_can_change_sells, only: :update
@@ -18,7 +18,7 @@ module Admin
end
def set_sells
enterprise = Enterprise.find(params[:id])
enterprise = Enterprise.find_by_permalink(params[:id]) || Enterprise.find(params[:id])
attributes = { sells: params[:sells] }
attributes[:producer_profile_only] = params[:sells] == "none" && !!params[:producer_profile_only]
attributes[:shop_trial_start_date] = Time.now if params[:sells] == "own"
@@ -53,7 +53,6 @@ module Admin
end
end
protected
def build_resource_with_address
@@ -64,6 +63,11 @@ module Admin
end
alias_method_chain :build_resource, :address
# Overriding method on Spree's resource controller,
# so that resources are found using permalink
def find_resource
Enterprise.find_by_permalink(params[:id])
end
private
@@ -76,8 +80,10 @@ module Admin
end
def collection
# TODO was ordered with is_distributor DESC as well, not sure why or how we want ot sort this now
Enterprise.managed_by(spree_current_user).order('is_primary_producer ASC, name')
# TODO was ordered with is_distributor DESC as well, not sure why or how we want to sort this now
OpenFoodNetwork::Permissions.new(spree_current_user).
editable_enterprises.
order('is_primary_producer ASC, name')
end
def collection_actions

View File

@@ -12,7 +12,7 @@ module Admin
end
def load_enterprise
@enterprise = Enterprise.find params[:enterprise_id]
@enterprise = Enterprise.find_by_permalink params[:enterprise_id]
end
def load_properties

View File

@@ -29,7 +29,7 @@ module Api
end
def update
@enterprise = Enterprise.find(params[:id])
@enterprise = Enterprise.find_by_permalink(params[:id]) || Enterprise.find(params[:id])
authorize! :update, @enterprise
if @enterprise.update_attributes(params[:enterprise])
@@ -40,7 +40,7 @@ module Api
end
def update_image
@enterprise = Enterprise.find(params[:id])
@enterprise = Enterprise.find_by_permalink(params[:id]) || Enterprise.find(params[:id])
authorize! :update, @enterprise
if params[:logo] && @enterprise.update_attributes( { logo: params[:logo] } )

View File

@@ -11,8 +11,19 @@ class BaseController < ApplicationController
include Spree::ProductsHelper
before_filter :check_order_cycle_expiry
def load_active_distributors
@active_distributors ||= Enterprise.distributors_with_active_order_cycles
end
private
def set_order_cycles
@order_cycles = OrderCycle.with_distributor(@distributor).active
# And default to the only order cycle if there's only the one
if @order_cycles.count == 1
current_order(true).set_order_cycle! @order_cycles.first
end
end
end

View File

@@ -1,6 +1,10 @@
class EnterprisesController < BaseController
layout "darkswarm"
helper Spree::ProductsHelper
include OrderCyclesHelper
before_filter :clean_permalink, only: :check_permalink
respond_to :js, only: :permalink_checker
def index
@enterprises = Enterprise.all
@@ -24,7 +28,7 @@ class EnterprisesController < BaseController
end
def show
@enterprise = Enterprise.find params[:id]
@enterprise = Enterprise.find_by_permalink(params[:id]) || Enterprise.find(params[:id])
# User can view this page if they've already chosen their distributor, or if this page
# is for a supplier, they may use it to select a distributor that sells this supplier's
@@ -53,7 +57,7 @@ class EnterprisesController < BaseController
end
def shop
distributor = Enterprise.is_distributor.find params[:id]
distributor = Enterprise.is_distributor.find_by_permalink(params[:id]) || Enterprise.is_distributor.find(params[:id])
order = current_order(true)
if order.distributor and order.distributor != distributor
@@ -67,6 +71,25 @@ class EnterprisesController < BaseController
order.order_cycle = order_cycle_options.first if order_cycle_options.count == 1
order.save!
redirect_to main_app.shop_path
require_distributor_chosen
set_order_cycles
load_active_distributors
end
def check_permalink
return render text: params[:permalink], status: 409 if Enterprise.find_by_permalink params[:permalink]
path = Rails.application.routes.recognize_path( "/#{ params[:permalink].to_s }" )
if path && path[:controller] == "cms_content"
render text: params[:permalink], status: 200
else
render text: params[:permalink], status: 409
end
end
private
def clean_permalink
params[:permalink] = params[:permalink].parameterize
end
end

View File

@@ -20,7 +20,7 @@ module OpenFoodNetwork
def add_variant
@cart = Cart.find(params[:cart_id])
distributor = Enterprise.find(params[:distributor_id])
distributor = Enterprise.find_by_permalink(params[:distributor_id])
order_cycle = OrderCycle.find(params[:order_cycle_id]) if params[:order_cycle_id]
if @cart.add_variant params[:variant_id], params[:quantity], distributor, order_cycle, current_currency
@@ -36,4 +36,4 @@ module OpenFoodNetwork
Spree::Config[:currency]
end
end
end
end

View File

@@ -1,10 +1,12 @@
require 'open_food_network/scope_product_to_hub'
class ShopController < BaseController
layout "darkswarm"
before_filter :require_distributor_chosen
before_filter :set_order_cycles
before_filter :load_active_distributors
def show
redirect_to main_app.enterprise_shop_path(current_distributor)
end
def products
@@ -34,20 +36,14 @@ class ShopController < BaseController
private
def set_order_cycles
@order_cycles = OrderCycle.with_distributor(@distributor).active
# And default to the only order cycle if there's only the one
if @order_cycles.count == 1
current_order(true).set_order_cycle! @order_cycles.first
end
end
def products_for_shop
current_order_cycle.andand
.valid_products_distributed_by(current_distributor).andand
.order(taxon_order).andand
.select { |p| !p.deleted? && p.has_stock_for_distribution?(current_order_cycle, current_distributor) }
if current_order_cycle
current_order_cycle.
valid_products_distributed_by(current_distributor).
order(taxon_order).
each { |p| p.scope_to_hub current_distributor }.
select { |p| !p.deleted? && p.has_stock_for_distribution?(current_order_cycle, current_distributor) }
end
end
def taxon_order

View File

@@ -5,9 +5,12 @@ require 'open_food_network/group_buy_report'
require 'open_food_network/order_grouper'
require 'open_food_network/customers_report'
require 'open_food_network/users_and_enterprises_report'
require 'open_food_network/order_cycle_management_report'
Spree::Admin::ReportsController.class_eval do
include Spree::ReportsHelper
REPORT_TYPES = {
orders_and_fulfillment: [
['Order Cycle Supplier Totals',:order_cycle_supplier_totals],
@@ -22,11 +25,14 @@ Spree::Admin::ReportsController.class_eval do
customers: [
["Mailing List", :mailing_list],
["Addresses", :addresses]
],
order_cycle_management: [
["Payment Methods Report", :payment_methods_report]
]
}
# Fetches user's distributors, suppliers and order_cycles
before_filter :load_data, only: [:customers, :products_and_inventory]
before_filter :load_data, only: [:customers, :products_and_inventory, :order_cycle_management]
# Render a partial for orders and fulfillment description
respond_override :index => { :html => { :success => lambda {
@@ -36,6 +42,8 @@ Spree::Admin::ReportsController.class_eval do
render_to_string(partial: 'products_and_inventory_description', layout: false, locals: {report_types: REPORT_TYPES[:products_and_inventory]}).html_safe
@reports[:customers][:description] =
render_to_string(partial: 'customers_description', layout: false, locals: {report_types: REPORT_TYPES[:customers]}).html_safe
@reports[:order_cycle_management][:description] =
render_to_string(partial: 'order_cycle_management_description', layout: false, locals: {report_types: REPORT_TYPES[:order_cycle_management]}).html_safe
} } }
@@ -50,8 +58,20 @@ Spree::Admin::ReportsController.class_eval do
@report_types = REPORT_TYPES[:customers]
@report_type = params[:report_type]
@report = OpenFoodNetwork::CustomersReport.new spree_current_user, params
render_report(@report.header, @report.table, params[:csv], "customers_#{timestamp}.csv")
end
render_report(@report.header, @report.table, params[:csv], "customers.csv")
def order_cycle_management
@report_types = REPORT_TYPES[:order_cycle_management]
@report_type = params[:report_type]
@report = OpenFoodNetwork::OrderCycleManagementReport.new spree_current_user, params
@search = Spree::Order.complete.not_state(:canceled).managed_by(spree_current_user).search(params[:q])
@orders = @search.result
render_report(@report.header, @report.table, params[:csv], "order_cycle_management_#{timestamp}.csv")
end
def orders_and_distributors
@@ -79,7 +99,7 @@ Spree::Admin::ReportsController.class_eval do
csv << @report.header
@report.table.each { |row| csv << row }
end
send_data csv_string, :filename => "orders_and_distributors.csv"
send_data csv_string, :filename => "orders_and_distributors_#{timestamp}.csv"
end
end
@@ -231,7 +251,7 @@ Spree::Admin::ReportsController.class_eval do
@header = header
@table = order_grouper.table(@line_items)
csv_file_name = "bulk_coop.csv"
csv_file_name = "bulk_coop_#{timestamp}.csv"
render_report(@header, @table, params[:csv], csv_file_name)
end
@@ -262,7 +282,7 @@ Spree::Admin::ReportsController.class_eval do
when "payments_by_payment_type"
table_items = payments
header = ["Payment State", "Distributor", "Payment Type", "Total ($)"]
header = ["Payment State", "Distributor", "Payment Type", "Total (#{currency_symbol})"]
columns = [ proc { |payments| payments.first.order.payment_state },
proc { |payments| payments.first.order.distributor.name },
@@ -279,7 +299,7 @@ Spree::Admin::ReportsController.class_eval do
when "itemised_payment_totals"
table_items = orders
header = ["Payment State", "Distributor", "Product Total ($)", "Shipping Total ($)", "Outstanding Balance ($)", "Total ($)"]
header = ["Payment State", "Distributor", "Product Total (#{currency_symbol})", "Shipping Total (#{currency_symbol})", "Outstanding Balance (#{currency_symbol})", "Total (#{currency_symbol})"]
columns = [ proc { |orders| orders.first.payment_state },
proc { |orders| orders.first.distributor.name },
@@ -296,7 +316,7 @@ Spree::Admin::ReportsController.class_eval do
when "payment_totals"
table_items = orders
header = ["Payment State", "Distributor", "Product Total ($)", "Shipping Total ($)", "Total ($)", "EFT ($)", "PayPal ($)", "Outstanding Balance ($)"]
header = ["Payment State", "Distributor", "Product Total (#{currency_symbol})", "Shipping Total (#{currency_symbol})", "Total (#{currency_symbol})", "EFT (#{currency_symbol})", "PayPal (#{currency_symbol})", "Outstanding Balance (#{currency_symbol})"]
columns = [ proc { |orders| orders.first.payment_state },
proc { |orders| orders.first.distributor.name },
@@ -315,7 +335,7 @@ Spree::Admin::ReportsController.class_eval do
else
table_items = payments
header = ["Payment State", "Distributor", "Payment Type", "Total ($)"]
header = ["Payment State", "Distributor", "Payment Type", "Total (#{currency_symbol})"]
columns = [ proc { |payments| payments.first.order.payment_state },
proc { |payments| payments.first.order.distributor.name },
@@ -335,7 +355,7 @@ Spree::Admin::ReportsController.class_eval do
@header = header
@table = order_grouper.table(table_items)
csv_file_name = "payments.csv"
csv_file_name = "payments_#{timestamp}.csv"
render_report(@header, @table, params[:csv], csv_file_name)
@@ -475,7 +495,7 @@ Spree::Admin::ReportsController.class_eval do
table_items = @line_items
@include_blank = 'All'
header = ["Hub", "Customer", "Email", "Phone", "Producer", "Product", "Variant", "Amount", "Item ($)", "Item + Fees ($)", "Dist ($)", "Ship ($)", "Total ($)", "Paid?",
header = ["Hub", "Customer", "Email", "Phone", "Producer", "Product", "Variant", "Amount", "Item (#{currency_symbol})", "Item + Fees (#{currency_symbol})", "Dist (#{currency_symbol})", "Ship (#{currency_symbol})", "Total (#{currency_symbol})", "Paid?",
"Shipping", "Delivery?", "Ship street", "Ship street 2", "Ship city", "Ship postcode", "Ship state", "Order notes"]
rsa = proc { |line_items| line_items.first.order.shipping_method.andand.require_ship_address }
@@ -567,7 +587,7 @@ Spree::Admin::ReportsController.class_eval do
@header = header
@table = order_grouper.table(table_items)
csv_file_name = "#{__method__}.csv"
csv_file_name = "#{params[:report_type]}_#{timestamp}.csv"
render_report(@header, @table, params[:csv], csv_file_name)
@@ -576,13 +596,13 @@ Spree::Admin::ReportsController.class_eval do
def products_and_inventory
@report_types = REPORT_TYPES[:products_and_inventory]
@report = OpenFoodNetwork::ProductsAndInventoryReport.new spree_current_user, params
render_report(@report.header, @report.table, params[:csv], "products_and_inventory.csv")
render_report(@report.header, @report.table, params[:csv], "products_and_inventory_#{timestamp}.csv")
end
def users_and_enterprises
# @report_types = REPORT_TYPES[:users_and_enterprises]
@report = OpenFoodNetwork::UsersAndEnterprisesReport.new params
render_report(@report.header, @report.table, params[:csv], "users_and_enterprises.csv")
render_report(@report.header, @report.table, params[:csv], "users_and_enterprises_#{timestamp}.csv")
end
def render_report (header, table, create_csv, csv_file_name)
@@ -620,7 +640,8 @@ Spree::Admin::ReportsController.class_eval do
:customers => {:name => "Customers", :description => 'Customer details'},
:products_and_inventory => {:name => "Products & Inventory", :description => ''},
:sales_total => { :name => "Sales Total", :description => "Sales Total For All Orders" },
:users_and_enterprises => { :name => "Users & Enterprises", :description => "Enterprise Ownership & Status" }
:users_and_enterprises => { :name => "Users & Enterprises", :description => "Enterprise Ownership & Status" },
:order_cycle_management => {:name => "Order Cycle Management", :description => ''}
}
# Return only reports the user is authorized to view.
reports.select { |action| can? action, :report }
@@ -634,4 +655,8 @@ Spree::Admin::ReportsController.class_eval do
end
total_units.round(3)
end
def timestamp
Time.now.strftime("%Y%m%d")
end
end

View File

@@ -33,25 +33,6 @@ Spree::OrdersController.class_eval do
end
end
def select_distributor
distributor = Enterprise.is_distributor.find params[:id]
order = current_order(true)
order.distributor = distributor
order.save!
redirect_to main_app.enterprise_path(distributor)
end
def deselect_distributor
order = current_order(true)
order.distributor = nil
order.save!
redirect_to root_path
end
def update_distribution
@order = current_order(true)

View File

@@ -33,6 +33,15 @@ module Admin
admin_inject_json_ams_array "ofn.admin", "producers", @producers, Api::Admin::IdNameSerializer
end
def admin_inject_enterprise_permissions
permissions =
{can_manage_shipping_methods: can?(:manage_shipping_methods, @enterprise),
can_manage_payment_methods: can?(:manage_payment_methods, @enterprise),
can_manage_enterprise_fees: can?(:manage_enterprise_fees, @enterprise)}
render partial: "admin/json/injection_ams", locals: {ngModule: "admin.enterprises", name: "enterprisePermissions", json: permissions.to_json}
end
def admin_inject_hub_permissions
render partial: "admin/json/injection_ams", locals: {ngModule: "ofn.admin", name: "hubPermissions", json: @hub_permissions.to_json}
end

View File

@@ -1,3 +1,5 @@
require 'spree/money_decorator'
module Spree
module ReportsHelper
def report_order_cycle_options(order_cycles)
@@ -7,5 +9,17 @@ module Spree
[ "#{oc.name} &nbsp; (#{orders_open_at} - #{orders_close_at})".html_safe, oc.id ]
end
end
def report_payment_method_options(orders)
orders.map { |o| o.payments.first.payment_method.andand.name }.uniq
end
def report_shipping_method_options(orders)
orders.map { |o| o.shipping_method.andand.name }.uniq
end
def currency_symbol
Spree::Money.currency_symbol
end
end
end

View File

@@ -56,20 +56,25 @@ class Enterprise < ActiveRecord::Base
validates :address, presence: true, associated: true
validates :email, presence: true
validates_presence_of :owner
validates :permalink, uniqueness: true, presence: true
validate :shopfront_taxons
validate :enforce_ownership_limit, if: lambda { owner_id_changed? && !owner_id.nil? }
validates_length_of :description, :maximum => 255
before_save :confirmation_check, if: lambda{ email_changed? }
before_save :confirmation_check, if: lambda { email_changed? }
before_validation :initialize_permalink, if: lambda { permalink.nil? }
before_validation :ensure_owner_is_manager, if: lambda { owner_id_changed? && !owner_id.nil? }
before_validation :set_unused_address_fields
after_validation :geocode_address
after_create :relate_to_owners_hubs
# TODO: Later versions of devise have a dedicated after_confirmation callback, so use that
after_update :welcome_after_confirm, if: lambda { confirmation_token_changed? && confirmation_token.nil? }
after_create :send_welcome_email, if: lambda { email_is_known? }
after_rollback :restore_permalink
scope :by_name, order('name')
scope :visible, where(:visible => true)
scope :confirmed, where('confirmed_at IS NOT NULL')
@@ -93,6 +98,7 @@ class Enterprise < ActiveRecord::Base
}
scope :is_primary_producer, where(:is_primary_producer => true)
scope :is_distributor, where('sells != ?', 'none')
scope :is_hub, where(sells: 'any')
scope :supplying_variant_in, lambda { |variants| joins(:supplied_products => :variants_including_master).where('spree_variants.id IN (?)', variants).select('DISTINCT enterprises.*') }
scope :with_supplied_active_products_on_hand, lambda {
joins(:supplied_products)
@@ -199,7 +205,7 @@ class Enterprise < ActiveRecord::Base
end
def to_param
"#{id}-#{name.parameterize}"
permalink
end
def relatives
@@ -290,6 +296,22 @@ class Enterprise < ActiveRecord::Base
shipping_methods.any? && payment_methods.available.any?
end
def self.find_available_permalink(test_permalink)
test_permalink = test_permalink.parameterize
test_permalink = "my-enterprise" if test_permalink.blank?
existing = Enterprise.select(:permalink).order(:permalink).where("permalink LIKE ?", "#{test_permalink}%").map(&:permalink)
if existing.empty?
test_permalink
else
used_indices = existing.map do |p|
p.slice!(/^#{test_permalink}/)
p.match(/^\d+$/).to_s.to_i
end.select{ |p| p }
options = (1..existing.length).to_a - used_indices
test_permalink + options.first.to_s
end
end
protected
def devise_mailer
@@ -330,7 +352,7 @@ class Enterprise < ActiveRecord::Base
end
def geocode_address
address.geocode if address.changed?
address.geocode if address.andand.changed?
end
def ensure_owner_is_manager
@@ -343,9 +365,30 @@ class Enterprise < ActiveRecord::Base
end
end
def relate_to_owners_hubs
hubs = owner.owned_enterprises.is_hub.where('enterprises.id != ?', self)
hubs.each do |hub|
EnterpriseRelationship.create!(parent: self,
child: hub,
permissions_list: [:add_to_order_cycle,
:manage_products,
:edit_profile])
end
end
def shopfront_taxons
unless preferred_shopfront_taxon_order =~ /\A((\d+,)*\d+)?\z/
errors.add(:shopfront_category_ordering, "must contain a list of taxons.")
end
end
def restore_permalink
# If the permalink has errors, reset it to it's original value, so we can update the form
self.permalink = permalink_was if permalink_changed? && errors[:permalink].present?
end
def initialize_permalink
self.permalink = Enterprise.find_available_permalink(name)
end
end

View File

@@ -52,6 +52,9 @@ class AbilityDecorator
can [:admin, :index, :create], Enterprise
can [:read, :edit, :update, :bulk_update, :set_sells, :resend_confirmation], Enterprise do |enterprise|
OpenFoodNetwork::Permissions.new(user).editable_enterprises.include? enterprise
end
can [:manage_payment_methods, :manage_shipping_methods, :manage_enterprise_fees], Enterprise do |enterprise|
user.enterprises.include? enterprise
end
@@ -128,7 +131,7 @@ class AbilityDecorator
end
# Reports page
can [:admin, :index, :customers, :group_buys, :bulk_coop, :payments, :orders_and_distributors, :orders_and_fulfillment, :products_and_inventory], :report
can [:admin, :index, :customers, :orders_and_distributors, :group_buys, :bulk_coop, :payments, :orders_and_fulfillment, :products_and_inventory, :order_cycle_management], :report
end

View File

@@ -0,0 +1,9 @@
Spree::AppConfiguration.class_eval do
# This file decorates the existing preferences file defined by Spree.
# It allows us to add our own global configuration variables, which
# we can allow to be modified in the UI by adding appropriate form
# elements to existing or new configuration pages.
# Tax Preferences
preference :products_require_tax_category, :boolean, default: false
end

View File

@@ -0,0 +1,15 @@
module Spree
InventoryUnit.class_eval do
def self.assign_opening_inventory(order)
return [] unless order.completed?
#increase inventory to meet initial requirements
order.line_items.each do |line_item|
# Scope variant to hub so that stock levels may be subtracted from VariantOverride.
line_item.variant.scope_to_hub order.distributor
increase(order, line_item.variant, line_item.quantity)
end
end
end
end

View File

@@ -26,7 +26,7 @@ Spree::LineItem.class_eval do
def price_with_adjustments
# EnterpriseFee#create_locked_adjustment applies adjustments on line items to their parent order,
# so line_item.adjustments returns an empty array
price + order.adjustments.where(source_id: id).sum(&:amount) / quantity
(price + order.adjustments.where(source_id: id).sum(&:amount) / quantity).round(2)
end
def single_display_amount_with_adjustments
@@ -34,9 +34,9 @@ Spree::LineItem.class_eval do
end
def amount_with_adjustments
# EnterpriseFee#create_locked_adjustment applies adjustments on line items to their parent order,
# so line_item.adjustments returns an empty array
amount + order.adjustments.where(source_id: id).sum(&:amount)
# We calculate from price_with_adjustments here rather than building our own value because
# rounding errors can produce discrepencies of $0.01.
price_with_adjustments * quantity
end
def display_amount_with_adjustments

View File

@@ -66,6 +66,12 @@ Spree::Order.class_eval do
where("state != ?", state)
}
scope :with_payment_method_name, lambda { |payment_method_name|
joins(:payments => :payment_method).
where('spree_payment_methods.name = ?', payment_method_name).
select('DISTINCT spree_orders.*')
}
# -- Methods
def products_available_from_new_distribution
@@ -95,6 +101,7 @@ Spree::Order.class_eval do
# Overridden to support max_quantity
def add_variant(variant, quantity = 1, max_quantity = nil, currency = nil)
line_items(:reload)
current_item = find_line_item_by_variant(variant)
if current_item
Bugsnag.notify(RuntimeError.new("Order populator weirdness"), {

View File

@@ -1,3 +1,5 @@
require 'open_food_network/scope_variant_to_hub'
Spree::OrderPopulator.class_eval do
def populate(from_hash, overwrite = false)
@distributor, @order_cycle = distributor_and_order_cycle
@@ -31,6 +33,7 @@ Spree::OrderPopulator.class_eval do
def attempt_cart_add(variant_id, quantity, max_quantity = nil)
quantity = quantity.to_i
variant = Spree::Variant.find(variant_id)
variant.scope_to_hub @distributor
if quantity > 0
if check_stock_levels(variant, quantity) &&
check_order_cycle_provided_for(variant) &&

View File

@@ -1,4 +1,8 @@
require 'open_food_network/scope_product_to_hub'
Spree::Product.class_eval do
include OpenFoodNetwork::ProductScopableToHub
# We have an after_destroy callback on Spree::ProductOptionType. However, if we
# don't specify dependent => destroy on this association, it is not called. See:
# https://github.com/rails/rails/issues/7618
@@ -20,7 +24,8 @@ Spree::Product.class_eval do
validates_associated :master, message: "^Price and On Hand must be valid"
validates_presence_of :supplier
validates :primary_taxon, presence: { message: "^Product Category can't be blank" }
validates :tax_category_id, presence: { message: "^Tax Category can't be blank" }, if: "Spree::Config.products_require_tax_category"
validates_presence_of :variant_unit, if: :has_variants?
validates_presence_of :variant_unit_scale,
if: -> p { %w(weight volume).include? p.variant_unit }
@@ -128,10 +133,6 @@ Spree::Product.class_eval do
self.product_distributions.find_by_distributor_id(distributor)
end
def variants_for(order_cycle, distributor)
self.variants.where('spree_variants.id IN (?)', order_cycle.variants_distributed_by(distributor))
end
# overriding to check self.on_demand as well
def has_stock?
has_variants? ? variants.any?(&:in_stock?) : (on_demand || master.in_stock?)
@@ -141,7 +142,7 @@ Spree::Product.class_eval do
# This product has stock for a distribution if it is available on-demand
# or if one of its variants in the distribution is in stock
(!has_variants? && on_demand) ||
variants_distributed_by(order_cycle, distributor).any? { |v| v.in_stock? }
variants_distributed_by(order_cycle, distributor).any?(&:in_stock?)
end
def variants_distributed_by(order_cycle, distributor)

View File

@@ -1,7 +1,10 @@
require 'open_food_network/scope_variant_to_hub'
require 'open_food_network/enterprise_fee_calculator'
require 'open_food_network/option_value_namer'
Spree::Variant.class_eval do
include OpenFoodNetwork::VariantScopableToHub
has_many :exchange_variants, dependent: :destroy
has_many :exchanges, through: :exchange_variants
@@ -9,12 +12,12 @@ Spree::Variant.class_eval do
accepts_nested_attributes_for :images
validates_presence_of :unit_value,
if: -> v { %w(weight volume).include? v.product.andand.variant_unit },
unless: :is_master
if: -> v { %w(weight volume).include? v.product.andand.variant_unit },
unless: :is_master
validates_presence_of :unit_description,
if: -> v { v.product.andand.variant_unit.present? && v.unit_value.nil? },
unless: :is_master
if: -> v { v.product.andand.variant_unit.present? && v.unit_value.nil? },
unless: :is_master
before_validation :update_weight_from_unit_value, if: -> v { v.product.present? }
after_save :update_units
@@ -39,6 +42,10 @@ Spree::Variant.class_eval do
select('DISTINCT spree_variants.*')
}
scope :for_distribution, lambda { |order_cycle, distributor|
where('spree_variants.id IN (?)', order_cycle.variants_distributed_by(distributor))
}
def price_with_fees(distributor, order_cycle)
price + fees_for(distributor, order_cycle)

View File

@@ -8,7 +8,37 @@ class VariantOverride < ActiveRecord::Base
where(hub_id: hubs)
}
def self.price_for(variant, hub)
VariantOverride.where(variant_id: variant, hub_id: hub).first.andand.price
def self.price_for(hub, variant)
self.for(hub, variant).andand.price
end
def self.count_on_hand_for(hub, variant)
self.for(hub, variant).andand.count_on_hand
end
def self.stock_overridden?(hub, variant)
count_on_hand_for(hub, variant).present?
end
def self.decrement_stock!(hub, variant, quantity)
vo = self.for(hub, variant)
if vo.nil?
Bugsnag.notify RuntimeError.new "Attempting to decrement stock level for a variant without a VariantOverride."
elsif vo.count_on_hand.blank?
Bugsnag.notify RuntimeError.new "Attempting to decrement stock level on a VariantOverride without a count_on_hand specified."
else
vo.decrement! :count_on_hand, quantity
end
end
private
def self.for(hub, variant)
VariantOverride.where(variant_id: variant, hub_id: hub).first
end
end

View File

@@ -52,6 +52,16 @@
%br/
= f.text_field :on_hand, class: 'fullwidth'
= f.error_message_on :on_hand
.twelve.columns.alpha
.six.columns.alpha &nbsp;
.three.columns
- if Spree::TaxCategory.any?
= render 'spree/admin/products/tax_category_form', f: f
- else
&nbsp;
.three.columns.omega
= render 'spree/admin/products/shipping_category_form', f: f
.twelve.columns.alpha
= f.field_container :description do
= f.label :product_description, t(:product_description)

View File

@@ -0,0 +1,6 @@
/ insert_before "[data-hook='shipment_vat']"
%div.field.align-center{ "data-hook" => "products_require_tax_category" }
= hidden_field_tag 'preferences[products_require_tax_category]', '0'
= check_box_tag 'preferences[products_require_tax_category]', '1', Spree::Config[:products_require_tax_category]
= label_tag nil, t(:products_require_tax_category)

View File

@@ -2,7 +2,7 @@
%figure#logo.columns.eight
- if current_distributor
%h1= link_to current_distributor.name, main_app.shop_enterprise_path(current_distributor)
%h1= link_to current_distributor.name, main_app.enterprise_shop_path(current_distributor)
.change-location= link_to 'Change Location', root_path
- else
%h1= link_to "OPEN FOOD NETWORK", root_path

View File

@@ -1,5 +1,5 @@
class Api::Admin::EnterpriseSerializer < ActiveModel::Serializer
attributes :name, :id, :is_primary_producer, :is_distributor, :sells, :category, :payment_method_ids, :shipping_method_ids
attributes :producer_profile_only, :email, :long_description
attributes :producer_profile_only, :email, :long_description, :permalink
attributes :preferred_shopfront_message, :preferred_shopfront_closed_message, :preferred_shopfront_taxon_order
end

View File

@@ -69,10 +69,8 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer
object.promo_image(:large) if object.promo_image.exists?
end
# TODO when ActiveSerializers supports URL helpers
# Then refactor. See readme https://github.com/rails-api/active_model_serializers
def path
"/enterprises/#{object.to_param}/shop"
enterprise_shop_path(object)
end
# Map svg icons.

View File

@@ -1,3 +1,5 @@
require 'open_food_network/scope_variant_to_hub'
class Api::ProductSerializer < ActiveModel::Serializer
# TODO
# Prices can't be cached? How?
@@ -41,6 +43,13 @@ class Api::CachedProductSerializer < ActiveModel::Serializer
has_one :master, serializer: Api::VariantSerializer
def variants
object.variants_for(options[:current_order_cycle], options[:current_distributor]).in_stock
# We use the in_stock? method here instead of the in_stock scope because we need to
# look up the stock as overridden by VariantOverrides, and the scope method is not affected
# by them.
object.variants.
for_distribution(options[:current_order_cycle], options[:current_distributor]).
each { |v| v.scope_to_hub options[:current_distributor] }.
select(&:in_stock?)
end
end

View File

@@ -1,30 +1,31 @@
= link_to_with_icon('icon-edit', 'Edit Profile', main_app.edit_admin_enterprise_path(enterprise), class: 'edit')
%br/
= link_to_delete_enterprise enterprise
%br/
- if can? :destroy, enterprise
= link_to_delete_enterprise enterprise
%br/
- if enterprise.is_primary_producer
= link_to_with_icon 'icon-dashboard', 'Properties', main_app.admin_enterprise_producer_properties_path(enterprise_id: enterprise.id)
= link_to_with_icon 'icon-dashboard', 'Properties', main_app.admin_enterprise_producer_properties_path(enterprise_id: enterprise)
(#{enterprise.producer_properties.count})
%br/
- if enterprise.is_distributor
- if can? :admin, Spree::PaymentMethod
- if can?(:admin, Spree::PaymentMethod) && can?(:manage_payment_methods, enterprise)
= link_to_with_icon 'icon-chevron-right', 'Payment Methods', spree.admin_payment_methods_path(enterprise_id: enterprise.id)
(#{enterprise.payment_methods.count})
- if enterprise.payment_methods.count == 0
%span.icon-exclamation-sign.with-tip{"data-powertip" => "This enterprise has no payment methods", style: "font-size: 16px;color: #DA5354"}
%br/
- if can? :admin, Spree::ShippingMethod
- if can?(:admin, Spree::ShippingMethod) && can?(:manage_shipping_methods, enterprise)
= link_to_with_icon 'icon-plane', 'Shipping Methods', spree.admin_shipping_methods_path(enterprise_id: enterprise.id)
(#{enterprise.shipping_methods.count})
- if enterprise.shipping_methods.count == 0
%span.icon-exclamation-sign.with-tip{"data-powertip" => "This enterprise has shipping methods", style: "font-size: 16px;color: #DA5354"}
%br/
- if can? :admin, EnterpriseFee
- if can?(:admin, EnterpriseFee) && can?(:manage_enterprise_fees, enterprise)
= link_to_with_icon 'icon-money', 'Enterprise Fees', main_app.admin_enterprise_fees_path(enterprise_id: enterprise.id)
(#{enterprise.enterprise_fees.count})
- if enterprise.enterprise_fees.count == 0

View File

@@ -1,4 +1,5 @@
= admin_inject_enterprise
= admin_inject_taxons
= admin_inject_payment_methods
= admin_inject_shipping_methods
= admin_inject_shipping_methods
= admin_inject_enterprise_permissions

View File

@@ -1,12 +1,10 @@
-# Not all inputs are ng inputs, they don't make the form dirty on change.
-# Not all inputs are ng inputs, they don't make the ng-form dirty on change.
-# ng-change is only valid for inputs, not for a form.
-# So we use onchange and have to get the scope to access the ng controller
-# The nav-check-callback is warning on leave if the form is dirty.
= form_for [main_app, :admin, @enterprise], html: { name: "enterprise",
"ng-app" => 'admin.enterprises',
"ng-submit" => "navClear()",
"ng-controller" => 'enterpriseCtrl',
"nav-check-callback" => 'enterpriseNavCallback',
'onchange' => 'angular.element(enterprise).scope().enterprise.$setDirty()',
} do |f|
.row

View File

@@ -2,8 +2,9 @@
%a.menu_item{ href: "", id: "{{ item.name.toLowerCase().replace(' ', '_') }}",
ng: { repeat: '(index,item) in menu.items | filter:{visible:true}',
click: 'select(index)',
show: 'showItem(item)',
class: '{ selected: item.selected}',
'class-odd' => "'odd'",
'class-even' => "'even'" } }
%i{ class: "{{item.icon_class}}" }
%span {{ item.name }}
%span {{ item.name }}

View File

@@ -1,6 +0,0 @@
- if can? :admin, EnterpriseFee
= render 'sidebar_enterprise_fees', f: f
- if can? :admin, Spree::PaymentMethod
= render 'sidebar_payment_methods', f: f
- if can? :admin, Spree::ShippingMethod
= render 'sidebar_shipping_methods', f: f

View File

@@ -1,20 +0,0 @@
- enterprise_fees_color = @enterprise_fees.count > 0 ? "blue" : "red"
.sidebar_item.four.columns.alpha#enterprise_fees{ ng: { show: 'Enterprise.category != "producer_hub"' } }
.four.columns.alpha.header{ class: "#{enterprise_fees_color}" }
%span.four.columns.alpha.centered Enterprise Fees
.four.columns.alpha.list{ class: "#{enterprise_fees_color}" }
- if @enterprise_fees.count > 0
- @enterprise_fees.each do |enterprise_fee|
%a.four.columns.alpha.list-item{ class: "#{cycle('odd','even')}", href: "#{main_app.admin_enterprise_fees_path}" }
%span.three.columns.alpha
= enterprise_fee.name
%span.one.column.omega
&nbsp;
- else
.four.columns.alpha.list-item.red
%span.three.columns.alpha None Available
%span.one.column.omega
%span.icon-remove-sign
%a.four.columns.alpha.button{ href: "#{main_app.admin_enterprise_fees_path}", class: "#{enterprise_fees_color}" }
CREATE NEW
%span.icon-arrow-right

View File

@@ -1,24 +0,0 @@
.sidebar_item.four.columns.alpha#payment_methods{ ng: { show: 'Enterprise.sells != "none"' } }
.four.columns.alpha.header{ ng: { class: "paymentMethodsColor()" } }
%span.four.columns.alpha.centered Payment Methods
.four.columns.alpha.list{ ng: { class: "paymentMethodsColor()" } }
- if @payment_methods.count > 0
-# = hidden_field_tag "enterprise[payment_method_ids][]", []
- @payment_methods.each do |payment_method|
%span.four.columns.alpha.list-item{ class: "#{cycle('odd','even')}", ng: { controller: 'paymentMethodCtrl', init: "findPaymentMethodByID(#{payment_method.id})" } }
%span.four.columns
%span.three.columns.alpha
%label
= f.check_box :payment_method_ids, { multiple: true, 'ng-model' => 'PaymentMethod.selected' }, payment_method.id, nil
= payment_method.name
%a.one.columns.omega{ href: "#{edit_admin_payment_method_path(payment_method)}" }
%span.icon-arrow-right
- else
.four.columns.alpha.list-item
%span.three.columns.alpha None Available
%span.one.column.omega
%span.icon-remove-sign
%a.four.columns.alpha.button{ href: "#{new_admin_payment_method_path}", ng: { class: "paymentMethodsColor()" } }
CREATE NEW
%span.icon-arrow-right

View File

@@ -1,23 +0,0 @@
.sidebar_item.four.columns.alpha#shipping_methods{ ng: { show: 'Enterprise.sells != "none"' } }
.four.columns.alpha.header{ ng: { class: "shippingMethodsColor()" } }
%span.four.columns.alpha.centered Shipping Methods
.four.columns.alpha.list{ ng: { class: "shippingMethodsColor()" } }
- if @shipping_methods.count > 0
- @shipping_methods.each do |shipping_method|
%span.four.columns.alpha.list-item{ class: "#{cycle('odd','even')}", ng: { controller: 'shippingMethodCtrl', init: "findShippingMethodByID(#{shipping_method.id})" } }
%span.four.columns
%span.three.columns.alpha
%label
= f.check_box :shipping_method_ids, { :multiple => true, 'ng-model' => 'ShippingMethod.selected' }, shipping_method.id, nil
= shipping_method.name
%a.one.columns.omega{ href: "#{edit_admin_shipping_method_path(shipping_method)}" }
%span.one.column.alpha.icon-arrow-right
- else
.four.columns.alpha.list-item
%span.three.columns.alpha None Available
%span.one.column.omega
%span.icon-remove-sign
%a.four.columns.alpha.button{ href: "#{new_admin_shipping_method_path}", ng: { class: "shippingMethodsColor()" } }
CREATE NEW
%span.icon-arrow-right

View File

@@ -66,10 +66,24 @@
= f.radio_button :visible, false
&nbsp;
= f.label :visible, "Not Visible", :value => "false"
.row{ ng: { show: "Enterprise.sells == 'own' || Enterprise.sells == 'any'" } }
.three.columns.alpha
%label Link to shop front
.with-tip{'data-powertip' => "A direct link to your shopfront on the Open Food Network."}
%a What's this?
.eight.columns.omega
= main_app.shop_enterprise_url(@enterprise)
.permalink{ ng: { controller: "permalinkCtrl" } }
.row{ ng: { show: "Enterprise.sells == 'own' || Enterprise.sells == 'any'" } }
.three.columns.alpha
= f.label :permalink, 'Permalink (no spaces)'
.with-tip{'data-powertip' => "This permalink is used to create the url to your shop: #{spree.root_url}your-shop-name/shop"}
%a What's this?
.six.columns
= f.text_field :permalink, { 'ng-model' => "Enterprise.permalink", placeholder: "eg. your-shop-name", 'ng-model-options' => "{ updateOn: 'default blur', debounce: {'default': 300, 'blur': 0} }" }
.two.columns.omega
%img.spinner{ src: "/assets/loading.gif", width: "30px", ng: { show: "checking" } }
%span{ ng: { class: 'availability.toLowerCase()', hide: "checking" } }
{{ availability }}
%i{ ng: { class: "{'icon-ok-sign': availability == 'Available', 'icon-remove-sign': availability == 'Unavailable'}" } }
.row{ ng: { show: "Enterprise.sells == 'own' || Enterprise.sells == 'any'" } }
.three.columns.alpha
%label Link to shop front
.with-tip{'data-powertip' => "A direct link to your shopfront on the Open Food Network."}
%a What's this?
.eight.columns.omega
= surround spree.root_url, "/shop" do
{{Enterprise.permalink}}

View File

@@ -8,7 +8,7 @@
.exchange-product-details
.supplier {{ product.supplier_name }}
%label
= check_box_tag 'order_cycle_outgoing_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}', 1, 1, 'ng-hide' => 'product.variants', 'ng-disabled' => 'product.variants.length > 0', 'ng-model' => 'exchange.variants[product.master_id]', 'id' => 'order_cycle_outgoing_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}'
= check_box_tag 'order_cycle_outgoing_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}', 1, 1, 'ng-hide' => 'product.variants.length > 0', 'ng-disabled' => 'product.variants.length > 0', 'ng-model' => 'exchange.variants[product.master_id]', 'id' => 'order_cycle_outgoing_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}'
%img{'ng-src' => '{{ product.image_url }}'}
{{ product.name }}
.exchange-product-variant{'ng-repeat' => 'variant in product.variants | filter:variantSuppliedToOrderCycle'}

View File

@@ -9,13 +9,13 @@
.exchange-product-details
%label
= check_box_tag 'order_cycle_incoming_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}', 1, 1, 'ng-hide' => 'product.variants', 'ng-disabled' => 'product.variants.length > 0', 'ng-model' => 'exchange.variants[product.master_id]', 'ofn-sync-distributions' => '{{ product.master_id }}', 'id' => 'order_cycle_incoming_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}'
= check_box_tag 'order_cycle_incoming_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}', 1, 1, 'ng-hide' => 'product.variants.length > 0', 'ng-disabled' => 'product.variants.length > 0', 'ng-model' => 'exchange.variants[product.master_id]', 'ofn-sync-distributions' => '{{ product.master_id }}', 'id' => 'order_cycle_incoming_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}'
%img{'ng-src' => '{{ product.image_url }}'}
{{ product.name }}
-# When the master variant is in the order cycle but the product has variants, we want to
-# be able to remove the master variant, since it serves no purpose. Display a checkbox to do so.
.exchange-product-variant{'ng-show' => 'exchange.variants[product.master_id] && product.variants'}
.exchange-product-variant{'ng-show' => 'exchange.variants[product.master_id] && product.variants.length > 0'}
%label
= check_box_tag 'order_cycle_incoming_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}', 1, 1, 'ng-model' => 'exchange.variants[product.master_id]', 'ofn-sync-distributions' => '{{ product.master_id }}', 'id' => 'order_cycle_incoming_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}'
Obsolete master

View File

@@ -2,7 +2,7 @@
- ng_controller = order_cycles_simple_view ? 'AdminSimpleEditOrderCycleCtrl' : 'AdminEditOrderCycleCtrl'
= form_for [main_app, :admin, @order_cycle], :url => '', :html => {:class => 'ng order_cycle', 'ng-app' => 'admin.order_cycles', 'ng-controller' => ng_controller, 'ng-submit' => 'submit()'} do |f|
= form_for [main_app, :admin, @order_cycle], :url => '', :html => {:class => 'ng order_cycle', 'ng-app' => 'admin.order_cycles', 'ng-controller' => ng_controller, 'ng-submit' => 'submit($event)'} do |f|
- if order_cycles_simple_view
= render 'simple_form', f: f
- else

View File

@@ -2,7 +2,7 @@
- ng_controller = order_cycles_simple_view ? 'AdminSimpleCreateOrderCycleCtrl' : 'AdminCreateOrderCycleCtrl'
= form_for [main_app, :admin, @order_cycle], :url => '', :html => {:class => 'ng order_cycle', 'ng-app' => 'admin.order_cycles', 'ng-controller' => ng_controller, 'ng-submit' => 'submit()'} do |f|
= form_for [main_app, :admin, @order_cycle], :url => '', :html => {:class => 'ng order_cycle', 'ng-app' => 'admin.order_cycles', 'ng-controller' => ng_controller, 'ng-submit' => 'submit($event)'} do |f|
- if order_cycles_simple_view
= render 'simple_form', f: f
- else

View File

@@ -23,8 +23,8 @@
-# Shop URL
-# %td &nbsp;
-# %td
-# %a{:href => "#{ main_app.shop_enterprise_url(@enterprise) }", :target => "_blank"}
-# = main_app.shop_enterprise_url(@enterprise)
-# %a{:href => "#{ main_app.enterprise_shop_url(@enterprise) }", :target => "_blank"}
-# = main_app.enterprise_shop_url(@enterprise)
-# %tr
-# %td &nbsp;
-# %tr

View File

@@ -12,7 +12,7 @@
%ul#supplier-distributors
- if @distributors.delete @enterprise
%li= link_to "Buy direct from the farm", shop_enterprise_path(@enterprise), {class: distributor_link_class(@enterprise)}
%li= link_to "Buy direct from the farm", enterprise_shop_path(@enterprise), {class: distributor_link_class(@enterprise)}
- @distributors.each do |distributor|
%li= render partial: "shared/distributor", object: distributor

View File

@@ -5,7 +5,7 @@ child suppliers: :producers do
attributes :id
end
node :path do |enterprise|
main_app.shop_enterprise_path(enterprise)
main_app.enterprise_shop_path(enterprise)
end
node :pickup do |hub|
hub.shipping_methods.where(:require_ship_address => false).present?

View File

@@ -2,9 +2,9 @@
-#.row
-#.panel
-#%p
-#%strong= link_to "Manage my account", account_path
-#%strong= link_to "Manage my account", account_path
-#- if enterprise_user?
-#%strong= link_to "Enterprise admin", admin_path
-#%strong= link_to "Enterprise admin", admin_path
-#- if order = last_completed_order
-#%dl
-#%dt Current Hub:
@@ -13,8 +13,8 @@
-#%dt Last hub:
-#%dd
-#- if order.distributor != current_distributor
-#= link_to "#{order.distributor.name}".html_safe, "",
-#= link_to "#{order.distributor.name}".html_safe, "",
-#{class: distributor_link_class(order.distributor),
-#"ng-click" => "emptyCart('#{main_app.shop_enterprise_path(order.distributor)}', $event)"}
-#"ng-click" => "emptyCart('#{main_app.enterprise_shop_path(order.distributor)}', $event)"}
-#- else
-#= order.distributor.name

View File

@@ -1,3 +1,3 @@
= succeed ',' do
= link_to "<strong>#{distributor.name}</strong>".html_safe, shop_enterprise_path(distributor), {class: distributor_link_class(distributor)}
= link_to "<strong>#{distributor.name}</strong>".html_safe, enterprise_shop_path(distributor), {class: distributor_link_class(distributor)}
%span.secondary= distributor.city

View File

@@ -1,9 +1,9 @@
%span.cart-span{"ng-controller" => "CartCtrl", "ng-class" => "{ dirty: Cart.dirty }"}
%span.cart-span{"ng-controller" => "CartCtrl", "ng-class" => "{ dirty: Cart.dirty || Cart.empty() }"}
%a#cart.icon{cart: true}
%span.nav-branded
%span.nav-branded
%i.ofn-i_027-shopping-cart
%span
{{ Cart.line_items_present().length }}
{{ Cart.total_item_count() }}
items
.joyride-tip-guide{"ng-class" => "{ in: open }", "ng-show" => "open"}
@@ -12,7 +12,7 @@
%h5 Your shopping cart
%ul
%li.product-cart{"ng-repeat" => "line_item in Cart.line_items_present()",
"ng-controller" => "LineItemCtrl"}
"ng-controller" => "LineItemCtrl", "id" => "cart-variant-{{ line_item.variant.id }}"}
.row
.columns.small-7
%small
@@ -20,22 +20,24 @@
%em {{ line_item.variant.unit_to_display }}
.columns.small-3.text-right
%small
{{line_item.quantity}}
%span.quantity {{ line_item.quantity }}
%i.ofn-i_009-close
{{ line_item.variant.price_with_fees | localizeCurrency }}
%span.price {{ line_item.variant.price_with_fees | localizeCurrency }}
.columns.small-2
%small
\=
%strong
.right {{ line_item.variant.totalPrice() | localizeCurrency }}
%strong
.total-price.right {{ line_item.variant.totalPrice() | localizeCurrency }}
%li.total-cart{"ng-show" => "Cart.line_items_present().length > 0"}
.row
.columns.small-6
%em Total:
%em Total:
.columns.small-6.text-right
%strong {{ Cart.total() | localizeCurrency }}
%strong {{ Cart.total() | localizeCurrency }}
.text-right
%a.button.primary.small{href: checkout_path, "ng-disabled" => "Cart.dirty"} Quick checkout
%a.button.secondary.tiny.add_to_cart{ href: cart_path, type: :submit, "ng-disabled" => "Cart.dirty || Cart.empty()", "ng-class" => "{ dirty: Cart.dirty }" }
{{ Cart.dirty ? 'Updating cart...' : (Cart.empty() ? 'Cart empty' : 'Edit your cart' ) }}
%a.button.primary.tiny{href: checkout_path, "ng-disabled" => "Cart.dirty || Cart.empty()"} Checkout now

View File

@@ -1,51 +0,0 @@
collection @products
attributes :id, :name, :permalink, :count_on_hand, :on_demand, :group_buy
node do |product|
{
notes: strip_tags(product.notes),
description: strip_tags(product.description),
price: product.master.price_with_fees(current_distributor, current_order_cycle)
}
end
child :supplier => :supplier do
attributes :id
end
child :primary_taxon => :primary_taxon do
extends 'json/taxon'
end
child :master => :master do
attributes :id, :is_master, :count_on_hand, :name_to_display, :unit_to_display, :count_on_hand, :on_demand
child :images => :images do
attributes :id, :alt
node do |img|
{:small_url => img.attachment.url(:small, false),
:large_url => img.attachment.url(:large, false)}
end
end
end
node :variants do |product|
product.variants_for(current_order_cycle, current_distributor).in_stock.map do |v|
{id: v.id,
is_master: v.is_master,
count_on_hand: v.count_on_hand,
name_to_display: v.name_to_display,
unit_to_display: v.unit_to_display,
on_demand: v.on_demand,
price: v.price_with_fees(current_distributor, current_order_cycle),
images: v.images.map { |i| {id: i.id, alt: i.alt, small_url: i.attachment.url(:small, false)} }
}
end
end
child :taxons => :taxons do |taxon|
attributes :id
end
child :properties => :properties do |property|
attributes :name, :presentation
end

View File

@@ -12,24 +12,24 @@
%form{action: cart_path}
.small-12.medium-4.large-3.columns
%input.button.primary.right.add_to_cart{type: :submit, value: "Your shopping cart",
"ng-disabled" => "Cart.dirty"}
%i.ofn-i_011-spinner.cart-spinner{"ng-show" => "Cart.dirty"}
%input.small.button.primary.right.add_to_cart{type: :submit, value: "{{ Cart.dirty ? 'Updating cart...' : (Cart.empty() ? 'Cart empty' : 'Edit your cart' ) }}", "ng-disabled" => "Cart.dirty || Cart.empty()", "ng-class" => "{ dirty: Cart.dirty }" }
%div.pad-top{bindonce: true}
%product.animate-repeat{"ng-controller" => "ProductNodeCtrl",
"ng-repeat" => "product in filteredProducts = (Products.products | products:query | taxons:activeTaxons) track by product.id "}
"ng-repeat" => "product in filteredProducts = (Products.products | products:query | taxons:activeTaxons) track by product.id ", "id" => "product-{{ product.id }}"}
= render partial: "shop/products/summary"
%shop-variant{variant: 'product.master', "bo-if" => "!product.hasVariants"}
%shop-variant{variant: 'variant', "ng-repeat" => "variant in product.variants track by variant.id"}
%shop-variant{variant: 'product.master', "bo-if" => "!product.hasVariants", "id" => "variant-{{ product.master.id }}"}
%shop-variant{variant: 'variant', "ng-repeat" => "variant in product.variants track by variant.id", "id" => "variant-{{ variant.id }}"}
%product{"ng-show" => "Products.loading"}
.row.summary
.small-12.columns.text-center
Loading products
Loading products...
.row
.small-12.columns.text-center
%img.spinner{ src: "/assets/loading.gif" }
%img.spinner{ src: "/assets/spinning-circles.svg" }
%div{"ng-show" => "filteredProducts.length == 0 && !Products.loading"}
.row.summary
@@ -41,6 +41,6 @@
.row
.small-12.columns
%form{action: cart_path}
%input.button.primary.right.add_to_cart{type: :submit, value: "Your shopping cart",
"ng-disabled" => "Cart.dirty"}
%i.ofn-i_011-spinner.cart-spinner{"ng-show" => "Cart.dirty"}
%input.small.button.primary.right.add_to_cart{type: :submit, value: "{{ Cart.dirty ? 'Updating cart...' : (Cart.empty() ? 'Cart empty' : 'Edit your cart' ) }}", "ng-disabled" => "Cart.dirty || Cart.empty()", "ng-class" => "{ dirty: Cart.dirty }" }

View File

@@ -1,19 +1,20 @@
.product-thumb
%a{"ng-click" => "triggerProductModal()"}
%i.ofn-i_057-expand
%img{"bo-src" => "product.primaryImageOrMissing", "ng-click" => "triggerProductModal()"}
.row.summary
.small-9.medium-10.large-11.columns.summary-header
.small-10.medium-10.large-11.columns.summary-header
%h3
%a{"ng-click" => "triggerProductModal()"}
{{ product.name }}
%em from
%span
%enterprise-modal
%i.ofn-i_036-producers
{{ enterprise.name }}
.small-3.medium-2.large-1.columns.text-center
%i.ofn-i_057-expand
%small
%em from
%span
%enterprise-modal
%i.ofn-i_036-producers
{{ enterprise.name }}
.small-2.medium-2.large-1.columns.text-center
.taxon-flag
%render-svg{path: "{{product.primary_taxon.icon}}"}

View File

@@ -95,7 +95,7 @@
%span{ :class => 'one column alpha', :style => 'text-align: center'} {{ column.visible && "&#10003;" || !column.visible && "&nbsp;" }}
%span{ :class => 'two columns omega' } {{column.name }}
%div.sixteen.columns.alpha#loading{ 'ng-if' => 'loading' }
%img.spinner{ src: "/assets/loading.gif" }
%img.spinner{ src: "/assets/spinning-circles.svg" }
%h1 LOADING ORDERS
%div{ :class => "sixteen columns alpha", 'ng-show' => '!loading && filteredLineItems.length == 0'}
%h1#no_results No orders found.

View File

@@ -0,0 +1,4 @@
= f.field_container :shipping_categories do
= f.label :shipping_category_id, t(:shipping_category)
= f.collection_select(:shipping_category_id, Spree::ShippingCategory.all, :id, :name, {:include_blank => true}, {:class => 'select2 fullwidth'})
= f.error_message_on :shipping_category_id

View File

@@ -0,0 +1,6 @@
= f.field_container :tax_category_id do
= f.label :tax_category_id, t(:tax_category)
%span.required *
%br
= f.collection_select(:tax_category_id, Spree::TaxCategory.all, :id, :name, {:include_blank => Spree::TaxCategory.count > 1}, {:class => "select2 fullwidth"})
= f.error_message_on :tax_category_id

View File

@@ -2,7 +2,7 @@
{{ api_error_msg }}
%div.sixteen.columns.alpha#loading{ 'ng-if' => 'loading' }
%img.spinner{ src: "/assets/loading.gif" }
%img.spinner{ src: "/assets/spinning-circles.svg" }
%h1 LOADING PRODUCTS
%div.sixteen.columns.alpha{ 'ng-show' => '!loading && filteredProducts.length == 0 && query.length==0' }

View File

@@ -0,0 +1,9 @@
.row.date-range-filter
= label_tag nil, t(:date_range)
%br
= label_tag nil, t(:start), :class => 'inline'
= f.text_field :completed_at_gt, :class => 'datetimepicker datepicker-from'
%span.range-divider
%i.icon-arrow-right
= f.text_field :completed_at_lt, :class => 'datetimepicker datepicker-to'
= label_tag nil, t(:end), :class => 'inline'

View File

@@ -0,0 +1,4 @@
%ul{style: "margin-left: 12pt"}
- report_types.each do |report_type|
%li
= link_to report_type[0], "#{order_cycle_management_admin_reports_url}?report_type=#{report_type[1]}"

View File

@@ -1,26 +1,19 @@
= form_for @search, :url => spree.bulk_coop_admin_reports_path do |f|
= label_tag nil, t(:date_range)
%br
.date-range-filter
%div{"class" => "left sub-field"}
= f.text_field :completed_at_gt, :class => 'datepicker'
%br
= label_tag nil, t(:start), :class => 'sub'
%div{"class" => "right sub-field"}
= f.text_field :completed_at_lt, :class => 'datepicker'
%br
= label_tag nil, t(:stop)
%br
= label_tag nil, "Distributor: "
= f.collection_select(:distributor_id_eq, @distributors, :id, :name, :include_blank => 'All')
%br
= render 'date_range_form', f: f
.row
.four.columns.alpha
= label_tag nil, "Distributor: "
= f.collection_select(:distributor_id_eq, @distributors, :id, :name, {:include_blank => 'All'}, {:class => "select2 fullwidth"})
= label_tag nil, "Report Type: "
%br
= select_tag(:report_type, options_for_select([['Bulk Co-op - Totals by Supplier',:bulk_coop_supplier_report],['Bulk Co-op - Allocation',:bulk_coop_allocation],['Bulk Co-op - Packing Sheets',:bulk_coop_packing_sheets],['Bulk Co-op - Customer Payments',:bulk_coop_customer_payments]], @report_type))
%br
%br
= check_box_tag :csv
= label_tag :csv, "Download as csv"
%br
%br
= button t(:search)
%br
%br

View File

@@ -1,23 +1,24 @@
= form_tag spree.customers_admin_reports_url do |f|
%br
= label_tag nil, "Distributor: "
= select_tag(:distributor_id,
options_from_collection_for_select(@distributors, :id, :name, params[:distributor_id]),
:include_blank => true)
.row
.four.columns.alpha
= label_tag nil, "Distributor: "
= select_tag(:distributor_id,
options_from_collection_for_select(@distributors, :id, :name, params[:distributor_id]),
{:include_blank => true, :class => "select2 fullwidth"})
%br
= label_tag nil, "Supplier: "
= select_tag(:supplier_id,
options_from_collection_for_select(@suppliers, :id, :name, params[:supplier_id]),
:include_blank => true)
.four.columns
= label_tag nil, "Supplier: "
= select_tag(:supplier_id,
options_from_collection_for_select(@suppliers, :id, :name, params[:supplier_id]),
{:include_blank => true, :class => "select2 fullwidth"})
%br
= label_tag nil, "Order Cycle: "
= select_tag(:order_cycle_id,
options_for_select(report_order_cycle_options(@order_cycles), params[:order_cycle_id]),
include_blank: true)
.six.columns
= label_tag nil, "Order Cycle: "
= select_tag(:order_cycle_id,
options_for_select(report_order_cycle_options(@order_cycles), params[:order_cycle_id]),
{:include_blank => true, :class => "select2 fullwidth"})
%br
= label_tag nil, "Report Type: "
= select_tag(:report_type, options_for_select(@report_types, @report_type))

View File

@@ -0,0 +1,44 @@
= form_tag spree.order_cycle_management_admin_reports_url do |f|
%br
= label_tag nil, "Order Cycle: "
= select_tag(:order_cycle_id,
options_for_select(report_order_cycle_options(@order_cycles), params[:order_cycle_id]),
include_blank: true)
%br
%br
= label_tag nil, "Payment Methods (hold Ctrl to select multiple payment methods)"
%br
= select_tag(:payment_method_name,
options_for_select(report_payment_method_options(@orders), params[:payment_method_name]),
multiple: true, include_blank: true, size: 10)
%br
%br
= label_tag nil, "Shipping Method: "
= select_tag(:shipping_method_name,
options_for_select(report_shipping_method_options(@orders), params[:shipping_method_name]),
include_blank: true)
%br
%br
= check_box_tag :csv
= label_tag :csv, "Download as csv"
%br
%br
= button t(:search)
%br
%br
%table#listing_order_payment_methods.index
%thead
%tr{'data-hook' => "orders_header"}
- @report.header.each do |heading|
%th=heading
%tbody
- @report.table.each do |row|
%tr
- row.each do |column|
%td= column
- if @report.table.empty?
%tr
%td{:colspan => "2"}= t(:none)

View File

@@ -1,19 +1,11 @@
= form_for @search, :url => spree.orders_and_distributors_admin_reports_path do |s|
= label_tag nil, t(:date_range)
%br
.date-range-filter
%div{"class" => "left sub-field"}
= s.text_field :completed_at_gt, :class => 'datepicker'
%br
= label_tag nil, t(:start), :class => 'sub'
%div{"class" => "right sub-field"}
= s.text_field :completed_at_lt, :class => 'datepicker'
%br
= label_tag nil, t(:stop)
= form_for @search, :url => spree.orders_and_distributors_admin_reports_path do |f|
= render 'date_range_form', f: f
= check_box_tag :csv
= label_tag :csv, "Download as csv"
%br
= button t(:search)
%br
%br
%table#listing_orders.index

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