mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-17 00:07:24 +00:00
Merge master
This commit is contained in:
7
Gemfile
7
Gemfile
@@ -13,9 +13,10 @@ gem 'spree', github: 'openfoodfoundation/spree', branch: '1-3-stable'
|
||||
gem 'spree_i18n', github: 'spree/spree_i18n', branch: '1-3-stable'
|
||||
gem 'spree_auth_devise', github: 'spree/spree_auth_devise', branch: '1-3-stable'
|
||||
|
||||
# Waiting on merge of PR #117
|
||||
# https://github.com/spree-contrib/better_spree_paypal_express/pull/117
|
||||
gem 'spree_paypal_express', :github => "openfoodfoundation/better_spree_paypal_express", :branch => "1-3-stable"
|
||||
# Our branch contains two changes
|
||||
# - Pass customer email and phone number to PayPal (merged to upstream master)
|
||||
# - Change type of password from string to password to hide it in the form
|
||||
gem 'spree_paypal_express', :github => "openfoodfoundation/better_spree_paypal_express", :branch => "hide-password"
|
||||
#gem 'spree_paypal_express', :github => "spree-contrib/better_spree_paypal_express", :branch => "1-3-stable"
|
||||
|
||||
gem 'delayed_job_active_record'
|
||||
|
||||
@@ -14,8 +14,8 @@ GIT
|
||||
|
||||
GIT
|
||||
remote: git://github.com/openfoodfoundation/better_spree_paypal_express.git
|
||||
revision: cdd61161ccd27cd8d183f9321422c7be113796b8
|
||||
branch: 1-3-stable
|
||||
revision: 840d973cd5bd3250b17674a624dad494aeb09eb3
|
||||
branch: hide-password
|
||||
specs:
|
||||
spree_paypal_express (2.0.3)
|
||||
paypal-sdk-merchant (= 1.106.1)
|
||||
|
||||
BIN
app/assets/images/ofn-logo-footer.png
Normal file
BIN
app/assets/images/ofn-logo-footer.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.6 KiB |
80
app/assets/images/ofn-logo-mobile.svg
Normal file
80
app/assets/images/ofn-logo-mobile.svg
Normal file
@@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
viewBox="0 0 300 104"
|
||||
enable-background="new 0 0 300 104"
|
||||
id="svg2"
|
||||
version="1.1"
|
||||
inkscape:version="0.48.3.1 r9886"
|
||||
sodipodi:docname="logo-black.svg"
|
||||
width="100%"
|
||||
height="100%">
|
||||
<metadata
|
||||
id="metadata24">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs22" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1280"
|
||||
inkscape:window-height="741"
|
||||
id="namedview20"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.8101934"
|
||||
inkscape:cx="126.57728"
|
||||
inkscape:cy="62.030566"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="27"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="g4" />
|
||||
<g
|
||||
id="g4"
|
||||
fill="#fff">
|
||||
<path
|
||||
d="M142.7 15.6c.4 3.2.4 7.5 0 10.7-.5 4.6-3.8 8.4-9.1 8.4s-8.5-3.8-9.1-8.4c-.4-3.2-.4-7.5 0-10.7.5-4.6 3.8-8.4 9.1-8.4s8.6 3.8 9.1 8.4m-5.3 10.7c.4-3.2.4-7.5 0-10.7-.2-1.7-1.4-3-3.7-3-2.3 0-3.5 1.4-3.7 3-.4 3.2-.4 7.5 0 10.7.2 1.7 1.4 3 3.7 3 2.3 0 3.5-1.3 3.7-3"
|
||||
id="path6"
|
||||
style="fill:#000000" />
|
||||
<path
|
||||
d="M156.4 7.6c4.4 0 8 3.6 8 8s-3.6 8-8 8H153c-.2 0-.4.2-.4.4v9.5c0 .4-.3.8-.8.8H148c-.4 0-.8-.3-.8-.8V8.4c0-.4.3-.8.8-.8h8.4zm-3.5 5.3c-.2 0-.4.2-.4.4v4.6c0 .2.2.4.4.4h3.4c1.4 0 2.7-1.2 2.7-2.7 0-1.4-1.2-2.7-2.7-2.7h-3.4zM172.9 28.6c0 .2.2.4.4.4h9c.4 0 .8.3.8.8v3.8c0 .4-.3.8-.8.8h-14c-.4 0-.8-.3-.8-.8V8.4c0-.4.3-.8.8-.8h13.8c.4 0 .8.3.8.8v3.8c0 .4-.3.8-.8.8h-8.9c-.2 0-.4.2-.4.4V18c0 .2.2.4.4.4h8.6c.4 0 .8.3.8.8V23c0 .4-.3.8-.8.8h-8.6c-.2 0-.4.2-.4.4v4.4zM199.4 34.3c-.6 0-.9-.3-1-.6l-5.2-13.4c-.1-.2-.3-.2-.3.1v13.2c0 .4-.3.8-.8.8h-3.8c-.4 0-.8-.3-.8-.8V8.4c0-.4.3-.8.8-.8h4.5c.6 0 .8.3 1 .7l5.2 14.5c.1.2.3.2.3-.1V8.4c0-.4.3-.8.8-.8h3.8c.4 0 .8.3.8.8v25.1c0 .4-.3.8-.8.8h-4.5zM224.4 24v9.5c0 .4-.3.8-.8.8h-3.8c-.4 0-.8-.3-.8-.8V8.4c0-.4.3-.8.8-.8h13.3c.4 0 .8.3.8.8v3.8c0 .4-.3.8-.8.8h-8.4c-.2 0-.4.2-.4.4V18c0 .2.2.4.4.4h8c.4 0 .8.3.8.8V23c0 .4-.3.8-.8.8h-8c-.1-.2-.3 0-.3.2M255.6 15.6c.4 3.2.4 7.5 0 10.7-.5 4.6-3.8 8.4-9.1 8.4s-8.5-3.8-9.1-8.4c-.4-3.2-.4-7.5 0-10.7.5-4.6 3.8-8.4 9.1-8.4s8.6 3.8 9.1 8.4m-5.3 10.7c.4-3.2.4-7.5 0-10.7-.2-1.7-1.4-3-3.7-3-2.3 0-3.5 1.4-3.7 3-.4 3.2-.4 7.5 0 10.7.2 1.7 1.4 3 3.7 3 2.3 0 3.5-1.3 3.7-3M278 15.6c.4 3.2.4 7.5 0 10.7-.5 4.6-3.8 8.4-9.1 8.4s-8.5-3.8-9.1-8.4c-.4-3.2-.4-7.5 0-10.7.5-4.6 3.8-8.4 9.1-8.4s8.5 3.8 9.1 8.4m-5.4 10.7c.4-3.2.4-7.5 0-10.7-.2-1.7-1.4-3-3.7-3-2.3 0-3.5 1.4-3.7 3-.4 3.2-.4 7.5 0 10.7.2 1.7 1.4 3 3.7 3 2.3 0 3.5-1.3 3.7-3"
|
||||
id="path8"
|
||||
style="fill:#000000" />
|
||||
<path
|
||||
d="M291.2 7.6c4.7 0 8 3.8 8.5 8.4.4 3.2.4 6.6 0 9.8-.5 4.6-3.8 8.4-8.5 8.4h-8c-.4 0-.8-.3-.8-.8v-25c0-.4.3-.8.8-.8h8zm-3 5.3c-.2 0-.4.2-.4.4v15.2c0 .2.2.4.4.4h3c1.8 0 2.9-1.4 3.1-3.1.4-3.2.4-6.6 0-9.8-.2-1.7-1.4-3.1-3.1-3.1h-3zM137.5 67.9c-.4 0-.6-.1-.8-.6l-9.1-20.8c-.1-.1-.3-.1-.3.1v20.6c0 .4-.3.7-.8.7h-.8c-.4 0-.8-.3-.8-.7V43.3c0-.4.3-.7.8-.7h2c.4 0 .6.1.8.6l9.1 20.6c.1.1.3.1.3-.1V43.3c0-.4.3-.7.8-.7h.8c.4 0 .8.3.8.7v23.9c0 .4-.3.7-.8.7h-2zM146.7 65.3c0 .2.2.4.4.4h9.9c.4 0 .8.3.8.7v.9c0 .4-.3.7-.8.7h-12c-.4 0-.8-.3-.8-.7v-24c0-.4.3-.7.8-.7h12c.4 0 .8.3.8.7v.9c0 .4-.3.7-.8.7h-9.9c-.2 0-.4.1-.4.4v8.2c0 .2.2.4.4.4h9.4c.4 0 .8.3.8.7v.8c0 .4-.3.7-.8.7h-9.4c-.2 0-.4.1-.4.4v8.8zM170 45.3v21.9c0 .4-.3.7-.8.7h-1c-.4 0-.8-.3-.8-.7V45.3c0-.2-.2-.4-.4-.4h-5.6c-.4 0-.8-.3-.8-.7v-.9c0-.4.3-.7.8-.7H176c.4 0 .8.3.8.7v.9c0 .4-.3.7-.8.7h-5.6c-.2 0-.4.2-.4.4M187 67.9h-2.1c-.3 0-.6-.2-.7-.5L179 43.3c-.1-.4.2-.7.8-.7h.9c.3 0 .6.1.7.5l4.3 20.7c0 .1.1.2.2.2h.1c.1 0 .2-.1.2-.2l4-20.7c.1-.4.4-.5.7-.5h1.3c.3 0 .6.2.7.5l4.3 20.7c0 .1.1.2.2.2h.1c.1 0 .2-.1.2-.2l4.6-20.7c.1-.4.4-.5.7-.5h.9c.6 0 .8.4.8.7l-5.5 24.1c-.1.4-.4.5-.7.5h-2.1c-.3 0-.6-.2-.7-.5l-4-19.3c0-.2-.3-.2-.3 0l-3.8 19.3c0 .4-.3.5-.6.5M223.9 49.8c.4 2.9.4 7.9 0 10.9-.6 4.7-3.9 7.5-8.5 7.5s-7.8-2.9-8.5-7.5c-.4-2.9-.4-8 0-10.9.6-3.9 3.5-7.5 8.5-7.5s7.9 3.6 8.5 7.5m-2.6 10.9c.5-3 .5-7.9 0-10.9-.4-2.6-2.3-5.2-5.9-5.2-3.6 0-5.5 2.6-5.9 5.2-.5 3-.5 7.9 0 10.9.3 2.1 1.8 5.2 5.9 5.2 4.1 0 5.6-3.1 5.9-5.2"
|
||||
id="path10"
|
||||
style="fill:#000000" />
|
||||
<path
|
||||
d="m 230.9,57.8 c -0.2,0 -0.4,0.1 -0.4,0.4 l 0,9 c 0,0.4 -0.3,0.7 -0.8,0.7 l -0.9,0 c -0.4,0 -0.8,-0.3 -0.8,-0.7 l 0,-23.9 c 0,-0.4 0.3,-0.7 0.8,-0.7 l 6.5,0 c 4.4,0 8,3.4 8,7.6 0,3.3 -1.8,5.2 -4.5,6.9 -0.5,0.3 -0.6,0.6 -0.3,1.2 l 4.8,8.6 c 0.3,0.5 0,1.1 -0.7,1.1 l -0.8,0 c -0.6,0 -0.9,-0.3 -1.1,-0.7 l -4.9,-9 c -0.1,-0.2 -0.3,-0.4 -0.7,-0.4 l -4.2,0 z m 0,-12.9 c -0.2,0 -0.4,0.1 -0.4,0.4 l 0,9.8 c 0,0.2 0.2,0.4 0.4,0.4 l 4.4,0 c 3,0 5.6,-2.4 5.6,-5.3 0,-2.9 -2.5,-5.3 -5.6,-5.3 z m 18.4,12.2 C 249.2,57 249,57 249,57.2 l 0,10 c 0,0.4 -0.3,0.7 -0.8,0.7 l -0.9,0 c -0.4,0 -0.8,-0.3 -0.8,-0.7 l 0,-23.9 c 0,-0.4 0.3,-0.7 0.8,-0.7 l 0.9,0 c 0.4,0 0.8,0.3 0.8,0.7 l 0,9.6 c 0,0.2 0.2,0.2 0.3,0.1 l 8.8,-10 c 0.1,-0.1 0.4,-0.4 1,-0.4 l 0.6,0 c 0.9,0 1.1,0.8 0.6,1.3 l -9.4,10.5 c -0.2,0.3 -0.3,0.5 0,0.9 L 261,66.6 c 0.4,0.5 0.3,1.3 -0.7,1.3 l -0.8,0 c -0.6,0 -0.8,-0.3 -1,-0.5 z"
|
||||
id="path12"
|
||||
style="fill:#000000"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cssssssssscccssccsccsssssssscssssssssssccssccccsscc" />
|
||||
<path
|
||||
d="m 3,44.3 0.5,0 c 1.2,0 2.2,-0.9 2.4,-2 0.5,-2.4 1.1,-4.7 2,-7 6.6,-18.2 23.5,-30.4 42,-30.4 18.5,0 35.4,12.2 42,30.3 0.8,2.2 1.5,4.6 2,6.9 0.3,1.3 1.6,2.2 2.9,1.9 1.3,-0.3 2.2,-1.6 1.9,-2.9 C 98.2,38.5 97.4,36 96.5,33.5 89.2,13.5 70.5,0 49.9,0 29.3,0 10.6,13.5 3.3,33.6 2.4,36.1 1.7,38.7 1.1,41.3 l 0,0.2 L 3.5,42 1.1,41.5 C 0.8,42.8 1.7,44.1 3,44.3 M 99.8,53 C 99.9,52 99.4,51 98.4,50.5 95,48.9 90.7,47.4 85.9,46.3 84.4,45.9 82.8,45.6 81.2,45.3 77.9,44.7 74.3,44.1 70.5,43.7 69.8,36.3 66.6,30.9 61,27.1 54.7,22.9 46.9,22.7 40.1,26.5 33.5,30.1 29.3,36.6 29,43.8 17.9,45.2 8.2,47.6 1.4,50.9 1.3,50.9 1.3,51 1.2,51 1.1,51 1.1,51.1 1,51.1 l -0.1,0.1 c -0.1,0.1 -0.2,0.1 -0.2,0.2 -0.4,0.4 -0.6,1 -0.6,1.6 0,1.4 0.1,2.7 0.2,4.1 0,0.4 0.1,0.7 0.1,1.1 0.3,2.6 0.8,5.2 1.5,7.7 0.2,0.7 0.3,1.4 0.5,2 0.3,0.9 0.6,1.7 0.9,2.6 0.7,1.8 1.4,3.6 2.2,5.2 0.8,1.6 1.7,3.1 2.6,4.6 0.7,1.2 1.5,2.3 2.4,3.5 1,1.3 2,2.6 3.2,3.8 1.5,1.7 3.1,3.2 4.8,4.6 1.4,1.2 2.9,2.3 4.4,3.3 1.9,1.3 3.8,2.4 5.9,3.4 2,0.9 4,1.8 6.1,2.4 2.1,0.7 4.3,1.2 6.5,1.6 2.8,0.5 5.7,0.8 8.7,0.8 l 0.1,0 c 13.6,0 26.5,-5.9 35.8,-15.9 1.8,-1.9 3.4,-3.9 4.9,-6.1 0.2,-0.2 0.3,-0.5 0.5,-0.7 1.5,-2.4 2.9,-4.8 4,-7.4 0.9,-2 1.6,-4 2.2,-6 1.3,-4.5 2.1,-9.5 2.2,-14.6 0,0.1 0,0.1 0,0 M 85.7,51.3 c 3.3,0.8 6.3,1.8 8.9,2.9 -3.4,1.6 -6.7,2.9 -9.9,4.1 -1.9,0.7 -3.7,1.2 -5.5,1.7 -3.5,1 -7.1,1.6 -10.7,2 1.3,-4.4 2,-8.8 2.2,-13.4 3.6,0.4 7,1 10.2,1.6 1.7,0.4 3.3,0.7 4.8,1.1 m -13,23.1 C 69.5,74.8 66.2,75 63,75 c 1.5,-2.5 2.7,-5.2 3.8,-7.8 3.6,-0.2 7,-0.7 10.4,-1.5 -1.3,2.9 -2.8,5.8 -4.5,8.7 m -9.8,12.5 c -2.8,0 -5.6,-0.1 -8.4,-0.5 1.9,-2.1 3.7,-4.3 5.4,-6.5 1.2,0.1 2.5,0.1 3.7,0.1 1.8,0 3.7,-0.1 5.5,-0.2 -1.9,2.4 -4,4.8 -6.2,7.1 M 40.2,82.4 c 1.6,-1.7 3,-3.4 4.4,-5.2 3.2,0.9 6.4,1.6 9.5,2 -1.7,2.1 -3.5,4.1 -5.4,6 -2.8,-0.7 -5.6,-1.6 -8.5,-2.8 M 6.6,65 C 6.1,63.1 5.7,61.2 5.4,59.2 c 7.2,-1.8 16.6,-1.4 26.2,1.3 -0.9,2 -2,3.9 -3.2,5.8 C 19.3,64 11.6,64.2 6.6,65 m 50.7,9.7 c -3.2,-0.3 -6.5,-0.9 -9.8,-1.7 1.4,-2.2 2.6,-4.5 3.7,-6.9 3.5,0.6 6.8,1 10.1,1.1 -1.1,2.5 -2.4,5.1 -4,7.5 M 42.7,71.4 c -1.5,-0.5 -3,-1.1 -4.5,-1.8 -1.7,-0.7 -3.3,-1.3 -4.9,-1.9 1.1,-1.9 2.2,-3.8 3.1,-5.8 3.5,1.2 6.8,2.2 10,3 -1.1,2.3 -2.4,4.5 -3.7,6.5 M 30.5,72 c 1.8,0.6 3.8,1.3 5.7,2.2 1.2,0.5 2.3,1 3.5,1.4 -1.3,1.7 -2.8,3.3 -4.3,4.8 -3.1,-1.2 -6.2,-2.3 -9.3,-3 1.5,-1.8 3,-3.6 4.4,-5.4 m 12,-41.3 c 5.2,-2.9 11.1,-2.7 15.8,0.4 4.2,2.8 6.5,6.7 7.3,12 -5,-0.4 -10.2,-0.6 -15.5,-0.6 -5.5,0 -10.9,0.3 -16,0.7 0.4,-5.1 3.5,-9.8 8.4,-12.5 m 7.5,16.8 2.1,0 c 1,0 2,0 3.1,0.1 3.6,0.1 7.2,0.3 10.6,0.6 -0.2,4.8 -1,9.5 -2.5,14.1 -3.2,0 -6.5,-0.3 -10,-0.9 -1.6,-0.3 -3.2,-0.6 -4.9,-1 -3.2,-0.7 -6.6,-1.7 -10.2,-3 -0.1,0 -0.2,-0.1 -0.3,-0.1 C 36.4,56.8 35,56.3 33.5,55.9 23.9,53.1 14.6,52.4 6.8,53.9 17.1,49.8 32.9,47.5 50,47.5 M 8.2,69.7 c 4.2,-0.5 10.1,-0.7 17.2,0.9 -1.5,1.9 -3.2,3.8 -5,5.5 -3.3,-0.5 -6.5,-0.8 -9.6,-0.7 -1,-1.8 -1.9,-3.7 -2.6,-5.7 m 9.5,15.2 c -1.1,-1.2 -2.2,-2.4 -3.2,-3.8 -0.2,-0.3 -0.4,-0.5 -0.6,-0.8 0.5,0 1,0 1.5,0.1 2,0.2 4.2,0.4 6.5,0.9 2.8,0.6 6,1.5 9.3,2.7 -2.5,2.1 -5.3,4.1 -8.2,5.8 -1.8,-1.4 -3.6,-3.1 -5.3,-4.9 m 9.9,8 c 3.2,-2 6.1,-4.3 8.8,-6.8 2.7,1.2 5.3,2.2 8,2.9 -3,2.6 -6.3,5.1 -10,7.1 -2.4,-0.8 -4.7,-1.9 -6.8,-3.2 m 13.1,5.2 c 3.5,-2.3 6.6,-5 9.4,-7.5 2.7,0.5 5.3,0.9 7.9,1.1 -3.2,3 -6.3,5.4 -9.4,7.4 -2.6,-0.2 -5.3,-0.5 -7.9,-1 m 17.1,0.2 c 2.4,-1.9 4.7,-4.1 7.2,-6.6 3.6,-0.1 7.2,-0.6 10.8,-1.3 -5.3,4 -11.5,6.7 -18,7.9 M 86.7,79.2 c -1.1,1.6 -2.3,3.1 -3.5,4.5 -4.4,1.2 -8.8,2.2 -13.2,2.7 2.1,-2.4 3.9,-4.9 5.6,-7.5 4.4,-0.7 8.8,-1.7 13.1,-3 -0.7,1.2 -1.3,2.2 -2,3.3 m -7.8,-5.9 c 1.6,-3.1 3,-6.2 4.1,-9.3 3.7,-1.2 7.4,-2.6 11.3,-4.3 -0.5,3.5 -1.5,6.9 -2.7,10.2 -4.2,1.4 -8.4,2.5 -12.7,3.4"
|
||||
id="path18"
|
||||
style="fill:#000000"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="csccsccsccscccccccccccccccscscscccscsccccccccsscccccccccccccccccccccccsccccccccccccccccccccccccccccccccscccscccccccccccccccccccccccccccccccccccccccccccccccc" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 9.7 KiB |
BIN
app/assets/images/ofn-logo.png
Normal file
BIN
app/assets/images/ofn-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.5 KiB |
@@ -38,6 +38,7 @@
|
||||
//= require ./products/products
|
||||
//= require ./shipping_methods/shipping_methods
|
||||
//= require ./side_menu/side_menu
|
||||
//= require ./tag_rules/tag_rules
|
||||
//= require ./taxons/taxons
|
||||
//= require ./utils/utils
|
||||
//= require ./users/users
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
angular.module("admin.customers").controller "customersCtrl", ($scope, Customers, Columns, pendingChanges, shops) ->
|
||||
$scope.shop = null
|
||||
angular.module("admin.customers").controller "customersCtrl", ($scope, CustomerResource, Columns, pendingChanges, shops) ->
|
||||
$scope.shop = {}
|
||||
$scope.shops = shops
|
||||
$scope.submitAll = pendingChanges.submitAll
|
||||
|
||||
@@ -8,10 +8,26 @@ angular.module("admin.customers").controller "customersCtrl", ($scope, Customers
|
||||
code: { name: "Code", visible: true }
|
||||
tags: { name: "Tags", visible: true }
|
||||
|
||||
$scope.$watch "shop", ->
|
||||
if $scope.shop?
|
||||
Customers.loaded = false
|
||||
$scope.customers = Customers.index(enterprise_id: $scope.shop.id)
|
||||
$scope.$watch "shop.id", ->
|
||||
if $scope.shop.id?
|
||||
$scope.customers = index {enterprise_id: $scope.shop.id}
|
||||
|
||||
$scope.loaded = ->
|
||||
Customers.loaded
|
||||
$scope.add = (email) ->
|
||||
params =
|
||||
enterprise_id: $scope.shop.id
|
||||
email: email
|
||||
CustomerResource.create params, (customer) =>
|
||||
if customer.id
|
||||
$scope.customers.push customer
|
||||
$scope.quickSearch = customer.email
|
||||
|
||||
$scope.deleteCustomer = (customer) ->
|
||||
params = id: customer.id
|
||||
CustomerResource.destroy params, ->
|
||||
i = $scope.customers.indexOf customer
|
||||
$scope.customers.splice i, 1 unless i < 0
|
||||
|
||||
index = (params) ->
|
||||
$scope.loaded = false
|
||||
CustomerResource.index params, =>
|
||||
$scope.loaded = true
|
||||
|
||||
@@ -1 +1 @@
|
||||
angular.module("admin.customers", ['ngResource', 'ngTagsInput', 'admin.indexUtils', 'admin.dropdown'])
|
||||
angular.module("admin.customers", ['ngResource', 'ngTagsInput', 'admin.indexUtils', 'admin.utils', 'admin.dropdown'])
|
||||
@@ -1,8 +0,0 @@
|
||||
angular.module("admin.customers").directive "tagsWithTranslation", ->
|
||||
restrict: "E"
|
||||
template: "<tags-input ng-model='object.tags'>"
|
||||
scope:
|
||||
object: "="
|
||||
link: (scope, element, attrs) ->
|
||||
scope.$watchCollection "object.tags", ->
|
||||
scope.object.tag_list = (tag.text for tag in scope.object.tags).join(",")
|
||||
@@ -1,8 +1,17 @@
|
||||
angular.module("admin.customers").factory 'CustomerResource', ($resource) ->
|
||||
$resource('/admin/customers.json', {}, {
|
||||
$resource('/admin/customers/:id.json', {}, {
|
||||
'index':
|
||||
method: 'GET'
|
||||
isArray: true
|
||||
params:
|
||||
enterprise_id: '@enterprise_id'
|
||||
'create':
|
||||
method: 'POST'
|
||||
params:
|
||||
enterprise_id: '@enterprise_id'
|
||||
email: '@email'
|
||||
'destroy':
|
||||
method: 'DELETE'
|
||||
params:
|
||||
id: '@id'
|
||||
})
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
angular.module("admin.customers").factory 'Customers', (CustomerResource) ->
|
||||
new class Customers
|
||||
customers: []
|
||||
customers_by_id: {}
|
||||
loaded: false
|
||||
|
||||
index: (params={}, callback=null) ->
|
||||
CustomerResource.index params, (data) =>
|
||||
for customer in data
|
||||
@customers.push customer
|
||||
@customers_by_id[customer.id] = customer
|
||||
|
||||
@loaded = true
|
||||
(callback || angular.noop)(@customers)
|
||||
|
||||
@customers
|
||||
@@ -17,8 +17,9 @@ angular.module("admin.enterprises")
|
||||
{ name: t('shipping_methods'), icon_class: "icon-truck", show: "showShippingMethods()" }
|
||||
{ name: t('payment_methods'), icon_class: "icon-money", show: "showPaymentMethods()" }
|
||||
{ name: t('enterprise_fees'), icon_class: "icon-tasks", show: "showEnterpriseFees()" }
|
||||
{ name: t('inventory_settings'), icon_class: "icon-list-ol", show: "showInventorySettings()" }
|
||||
{ name: t('shop_preferences'), icon_class: "icon-shopping-cart", show: "showShopPreferences()" }
|
||||
{ name: t('inventory_settings'), icon_class: "icon-list-ol", show: "enterpriseIsShop()" }
|
||||
{ name: t('tag_rules'), icon_class: "icon-random", show: "enterpriseIsShop()" }
|
||||
{ name: t('shop_preferences'), icon_class: "icon-shopping-cart", show: "enterpriseIsShop()" }
|
||||
]
|
||||
|
||||
$scope.select(0)
|
||||
@@ -42,8 +43,5 @@ angular.module("admin.enterprises")
|
||||
$scope.showEnterpriseFees = ->
|
||||
enterprisePermissions.can_manage_enterprise_fees && ($scope.Enterprise.sells != "none" || $scope.Enterprise.is_primary_producer)
|
||||
|
||||
$scope.showInventorySettings = ->
|
||||
$scope.Enterprise.sells != "none"
|
||||
|
||||
$scope.showShopPreferences = ->
|
||||
$scope.enterpriseIsShop = ->
|
||||
$scope.Enterprise.sells != "none"
|
||||
|
||||
@@ -1 +1 @@
|
||||
angular.module("admin.enterprises", [
|
||||
angular.module("admin.enterprises", [
|
||||
@@ -15,8 +15,6 @@ angular.module("admin.indexUtils").directive "ofnSelect2", ($sanitize, $timeout)
|
||||
element.select2
|
||||
minimumResultsForSearch: scope.minSearch || 0
|
||||
data: { results: scope.data, text: scope.text }
|
||||
initSelection: (element, callback) ->
|
||||
callback scope.data[0]
|
||||
formatSelection: (item) ->
|
||||
item[scope.text]
|
||||
formatResult: (item) ->
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
angular.module("admin.payment_methods")
|
||||
angular.module("admin.paymentMethods")
|
||||
.controller "paymentMethodCtrl", ($scope, PaymentMethods) ->
|
||||
$scope.findPaymentMethodByID = (id) ->
|
||||
$scope.PaymentMethod = PaymentMethods.findByID(id)
|
||||
$scope.PaymentMethod = PaymentMethods.findByID(id)
|
||||
|
||||
@@ -1 +1 @@
|
||||
angular.module("admin.payment_methods", [])
|
||||
angular.module("admin.paymentMethods", [])
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
angular.module("admin.payment_methods")
|
||||
angular.module("admin.paymentMethods")
|
||||
.factory "PaymentMethods", (paymentMethods) ->
|
||||
new class PaymentMethods
|
||||
paymentMethods: paymentMethods
|
||||
|
||||
@@ -1,4 +1,2 @@
|
||||
angular.module("admin.shipping_methods")
|
||||
.controller "shippingMethodCtrl", ($scope, ShippingMethods) ->
|
||||
$scope.findShippingMethodByID = (id) ->
|
||||
$scope.ShippingMethod = ShippingMethods.findByID(id)
|
||||
angular.module("admin.shippingMethods").controller "shippingMethodCtrl", ($scope, shippingMethod) ->
|
||||
$scope.shippingMethod = shippingMethod
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
angular.module("admin.shippingMethods")
|
||||
.controller "shippingMethodsCtrl", ($scope, ShippingMethods) ->
|
||||
$scope.findShippingMethodByID = (id) ->
|
||||
$scope.ShippingMethod = ShippingMethods.findByID(id)
|
||||
@@ -1,4 +1,4 @@
|
||||
angular.module("admin.shipping_methods")
|
||||
angular.module("admin.shippingMethods")
|
||||
.factory "ShippingMethods", (shippingMethods) ->
|
||||
new class ShippingMethods
|
||||
shippingMethods: shippingMethods
|
||||
|
||||
@@ -1 +1 @@
|
||||
angular.module("admin.shipping_methods", [])
|
||||
angular.module("admin.shippingMethods", ["ngTagsInput", 'admin.utils'])
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
angular.module("admin.tagRules").controller "TagRulesCtrl", ($scope, $http, enterprise) ->
|
||||
$scope.tagGroups = enterprise.tag_groups
|
||||
|
||||
$scope.visibilityOptions = [ { id: "visible", name: "VISIBLE" }, { id: "hidden", name: "NOT VISIBLE" } ]
|
||||
|
||||
updateRuleCounts = ->
|
||||
index = 0
|
||||
for tagGroup in $scope.tagGroups
|
||||
tagGroup.startIndex = index
|
||||
index = index + tagGroup.rules.length
|
||||
|
||||
updateRuleCounts()
|
||||
|
||||
$scope.updateTagsRulesFor = (tagGroup) ->
|
||||
for tagRule in tagGroup.rules
|
||||
tagRule.preferred_customer_tags = (tag.text for tag in tagGroup.tags).join(",")
|
||||
|
||||
$scope.addNewRuleTo = (tagGroup, ruleType) ->
|
||||
newRule =
|
||||
id: null
|
||||
preferred_customer_tags: (tag.text for tag in tagGroup.tags).join(",")
|
||||
type: "TagRule::#{ruleType}"
|
||||
switch ruleType
|
||||
when "DiscountOrder"
|
||||
newRule.calculator = { preferred_flat_percent: 0 }
|
||||
when "FilterShippingMethods"
|
||||
newRule.peferred_shipping_method_tags = []
|
||||
newRule.preferred_matched_shipping_methods_visibility = "visible"
|
||||
tagGroup.rules.push(newRule)
|
||||
updateRuleCounts()
|
||||
|
||||
$scope.addNewTag = ->
|
||||
$scope.tagGroups.push { tags: [], rules: [] }
|
||||
|
||||
$scope.deleteTagRule = (tagGroup, tagRule) ->
|
||||
index = tagGroup.rules.indexOf(tagRule)
|
||||
return unless index >= 0
|
||||
if tagRule.id is null
|
||||
tagGroup.rules.splice(index, 1)
|
||||
updateRuleCounts()
|
||||
else
|
||||
if confirm("Are you sure?")
|
||||
$http
|
||||
method: "DELETE"
|
||||
url: "/admin/enterprises/#{enterprise.id}/tag_rules/#{tagRule.id}.json"
|
||||
.success ->
|
||||
tagGroup.rules.splice(index, 1)
|
||||
updateRuleCounts()
|
||||
@@ -0,0 +1,11 @@
|
||||
angular.module("admin.tagRules").directive "invertNumber", ->
|
||||
restrict: "A"
|
||||
require: "ngModel"
|
||||
link: (scope, element, attrs, ngModel) ->
|
||||
ngModel.$parsers.push (viewValue) ->
|
||||
return -parseInt(viewValue) unless isNaN(parseInt(viewValue))
|
||||
viewValue
|
||||
|
||||
ngModel.$formatters.push (modelValue) ->
|
||||
return -parseInt(modelValue) unless isNaN(parseInt(modelValue))
|
||||
modelValue
|
||||
@@ -0,0 +1,34 @@
|
||||
angular.module("admin.tagRules").directive 'newTagRuleDialog', ($compile, $templateCache, $window) ->
|
||||
restrict: 'A'
|
||||
scope: true
|
||||
link: (scope, element, attr) ->
|
||||
# Compile modal template
|
||||
template = $compile($templateCache.get('admin/new_tag_rule_dialog.html'))(scope)
|
||||
|
||||
scope.ruleTypes = [
|
||||
# { id: "DiscountOrder", name: 'Apply a discount to orders' }
|
||||
{ id: "FilterShippingMethods", name: 'Show/Hide shipping methods' }
|
||||
]
|
||||
|
||||
scope.ruleType = "DiscountOrder"
|
||||
|
||||
# Set Dialog options
|
||||
template.dialog
|
||||
show: { effect: "fade", duration: 400 }
|
||||
hide: { effect: "fade", duration: 300 }
|
||||
autoOpen: false
|
||||
resizable: false
|
||||
width: $window.innerWidth * 0.4;
|
||||
modal: true
|
||||
open: (event, ui) ->
|
||||
$('.ui-widget-overlay').bind 'click', ->
|
||||
$(this).siblings('.ui-dialog').find('.ui-dialog-content').dialog('close')
|
||||
|
||||
# Link opening of dialog to click event on element
|
||||
element.bind 'click', (e) ->
|
||||
template.dialog('open')
|
||||
|
||||
scope.addRule = (tagGroup, ruleType) ->
|
||||
scope.addNewRuleTo(tagGroup, ruleType)
|
||||
template.dialog('close')
|
||||
return
|
||||
@@ -0,0 +1,4 @@
|
||||
angular.module("admin.tagRules").directive "discountOrder", ->
|
||||
restrict: "E"
|
||||
replace: true
|
||||
templateUrl: "admin/tag_rules/discount_order.html"
|
||||
@@ -0,0 +1,4 @@
|
||||
angular.module("admin.tagRules").directive "filterShippingMethods", ->
|
||||
restrict: "E"
|
||||
replace: true
|
||||
templateUrl: "admin/tag_rules/filter_shipping_methods.html"
|
||||
@@ -0,0 +1 @@
|
||||
angular.module("admin.tagRules", ['ngTagsInput'])
|
||||
@@ -0,0 +1,15 @@
|
||||
angular.module("admin.utils").directive "tagsWithTranslation", ($timeout) ->
|
||||
restrict: "E"
|
||||
template: "<tags-input ng-model='object[tagsAttr]'>"
|
||||
scope:
|
||||
object: "="
|
||||
tagsAttr: "@?"
|
||||
tagListAttr: "@?"
|
||||
link: (scope, element, attrs) ->
|
||||
$timeout ->
|
||||
scope.tagsAttr ||= "tags"
|
||||
scope.tagListAttr ||= "tag_list"
|
||||
|
||||
watchString = "object.#{scope.tagsAttr}"
|
||||
scope.$watchCollection watchString, ->
|
||||
scope.object[scope.tagListAttr] = (tag.text for tag in scope.object[scope.tagsAttr]).join(",")
|
||||
@@ -8,6 +8,7 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, $timeout, Enterpris
|
||||
$scope.show_profiles = false
|
||||
$scope.filtersActive = false
|
||||
$scope.distanceMatchesShown = false
|
||||
$scope.filterExpression = {active: true}
|
||||
|
||||
|
||||
$scope.$watch "query", (query)->
|
||||
@@ -44,8 +45,8 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, $timeout, Enterpris
|
||||
$scope.filterEnterprises = ->
|
||||
es = Enterprises.hubs
|
||||
$scope.nameMatches = enterpriseMatchesNameQueryFilter(es, true)
|
||||
$scope.distanceMatches = enterpriseMatchesNameQueryFilter(es, false)
|
||||
$scope.distanceMatches = distanceWithinKmFilter($scope.distanceMatches, 50)
|
||||
noNameMatches = enterpriseMatchesNameQueryFilter(es, false)
|
||||
$scope.distanceMatches = distanceWithinKmFilter(noNameMatches, 50)
|
||||
|
||||
|
||||
$scope.updateVisibleMatches = ->
|
||||
@@ -65,3 +66,9 @@ Darkswarm.controller "EnterprisesCtrl", ($scope, $rootScope, $timeout, Enterpris
|
||||
$scope.nameMatchesFiltered[0]
|
||||
else
|
||||
undefined
|
||||
|
||||
$scope.showClosedShops = ->
|
||||
delete $scope.filterExpression['active']
|
||||
|
||||
$scope.hideClosedShops = ->
|
||||
$scope.filterExpression['active'] = true
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
Darkswarm.directive 'auth', (AuthenticationService) ->
|
||||
restrict: 'A'
|
||||
link: (scope, elem, attrs) ->
|
||||
elem.bind "click", ->
|
||||
AuthenticationService.open '/' + attrs.auth
|
||||
@@ -0,0 +1,10 @@
|
||||
#new-tag-rule-dialog
|
||||
.text-normal.margin-bottom-30.text-center
|
||||
Select a rule type:
|
||||
|
||||
.text-center.margin-bottom-30
|
||||
-# %select.fullwidth{ 'select2-min-search' => 5, 'ng-model' => 'newRuleType', 'ng-options' => 'ruleType.id as ruleType.name for ruleType in availableRuleTypes' }
|
||||
%input.ofn-select2.fullwidth{ :id => 'rule_type_selector', ng: { model: "ruleType" }, data: "ruleTypes", 'min-search' => "5" }
|
||||
|
||||
.text-center
|
||||
%input.button.red.icon-plus{ type: 'button', value: "Add Rule", ng: { click: 'addRule(tagGroup, ruleType)' } }
|
||||
@@ -0,0 +1,37 @@
|
||||
%div
|
||||
%input{ type: "hidden",
|
||||
id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_id",
|
||||
name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][id]",
|
||||
ng: { value: "rule.id" } }
|
||||
|
||||
%input{ type: "hidden",
|
||||
id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_type",
|
||||
name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][type]",
|
||||
value: "TagRule::DiscountOrder" }
|
||||
|
||||
%input{ type: "hidden",
|
||||
id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_preferred_customer_tags",
|
||||
name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][preferred_customer_tags]",
|
||||
ng: { value: "rule.preferred_customer_tags" } }
|
||||
|
||||
%input{ type: "hidden",
|
||||
id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_calculator_type",
|
||||
name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][calculator_type]",
|
||||
value: "Spree::Calculator::FlatPercentItemTotal" }
|
||||
|
||||
%input{ type: "hidden",
|
||||
id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_calculator_attributes_id",
|
||||
name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][calculator_attributes][id]",
|
||||
ng: { value: "rule.calculator.id" } }
|
||||
|
||||
%input{ type: "hidden",
|
||||
name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][calculator_attributes][preferred_flat_percent]",
|
||||
ng: { value: "rule.calculator.preferred_flat_percent" } }
|
||||
|
||||
%span.text-normal {{ $index + 1 }}. Orders are discounted by
|
||||
%input{ type: "number",
|
||||
id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_calculator_attributes_preferred_flat_percent",
|
||||
min: -100,
|
||||
max: 100,
|
||||
ng: { model: "rule.calculator.preferred_flat_percent" }, 'invert-number' => true }
|
||||
%span.text-normal %
|
||||
@@ -0,0 +1,27 @@
|
||||
%div
|
||||
%input{ type: "hidden",
|
||||
id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_id",
|
||||
name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][id]",
|
||||
ng: { value: "rule.id" } }
|
||||
|
||||
%input{ type: "hidden",
|
||||
id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_type",
|
||||
name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][type]",
|
||||
value: "TagRule::FilterShippingMethods" }
|
||||
|
||||
%input{ type: "hidden",
|
||||
id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_preferred_customer_tags",
|
||||
name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][preferred_customer_tags]",
|
||||
ng: { value: "rule.preferred_customer_tags" } }
|
||||
|
||||
%input{ type: "hidden",
|
||||
id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_preferred_shipping_method_tags",
|
||||
name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][preferred_shipping_method_tags]",
|
||||
ng: { value: "rule.preferred_customer_tags" } }
|
||||
|
||||
%span.text-normal {{ $index + 1 }}. Shipping methods with matching tags are
|
||||
%input.light.ofn-select2{ id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_preferred_matched_shipping_methods_visibility",
|
||||
name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][preferred_matched_shipping_methods_visibility]",
|
||||
ng: { model: "rule.preferred_matched_shipping_methods_visibility"},
|
||||
data: 'visibilityOptions', "min-search" => 5 }
|
||||
-# %tags-with-translation{ object: "rule", "tags-attr" => "shipping_method_tags", "tag-list-attr" => "preferred_shipping_method_tags" }
|
||||
88
app/assets/stylesheets/admin/components/jquery_dialog.scss
Normal file
88
app/assets/stylesheets/admin/components/jquery_dialog.scss
Normal file
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
Main colors:
|
||||
dark: #545454
|
||||
light: #ccc
|
||||
*/
|
||||
.ui-dialog {
|
||||
border: 2px solid #4a4a4a;
|
||||
border-radius:3px;
|
||||
padding:0px;
|
||||
-moz-box-shadow: 3px 3px 4px #797979;
|
||||
-webkit-box-shadow: 3px 3px 4px #797979;
|
||||
box-shadow: 3px 3px 4px #797979;
|
||||
|
||||
/* For IE 8 */
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Shadow(Strength=4, Direction=135, Color='#545454')";
|
||||
|
||||
/* For IE 5.5 - 7 */
|
||||
filter: progid:DXImageTransform.Microsoft.Shadow(Strength=4, Direction=135, Color='#545454');
|
||||
}
|
||||
|
||||
.ui-dialog .ui-dialog-titlebar{
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.ui-dialog .ui-state-hover {
|
||||
&.ui-dialog-titlebar-close{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*.ui-dialog .ui-icon-closethick{background:url(/static/assets/dialogCloseButton.png);}*/
|
||||
|
||||
.ui-dialog .ui-widget-header{
|
||||
background-image: none;
|
||||
background-color: #ffffff;
|
||||
border:0px;
|
||||
border-radius: 3px;
|
||||
padding: 0px 5px 0px 5px;
|
||||
}
|
||||
.ui-dialog .ui-widget-content{
|
||||
border: none;
|
||||
border-radius: 3px;
|
||||
padding: 0px 50px 30px 50px;
|
||||
}
|
||||
|
||||
.ui-dialog .ui-corner-all{
|
||||
border-radius:0px;
|
||||
}
|
||||
.ui-dialog {
|
||||
.ui-state-hover, .ui-state-focus{
|
||||
border: none;
|
||||
background: none;
|
||||
color: #545454;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-state-hover, .ui-widget-header .ui-state-hover, .ui-widget-content .ui-state-hover {
|
||||
background-color: #ffffff;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.ui-dialog-titlebar-close {
|
||||
float: right;
|
||||
&:before {
|
||||
color: #000000;
|
||||
font-size: 2em;
|
||||
font-weight: 400;
|
||||
content: '\00d7';
|
||||
display: inline;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&:before {
|
||||
color: #da5354;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-icon {
|
||||
&.ui-icon-closethick {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ui-widget-overlay {
|
||||
background: #e9e9e9;
|
||||
opacity: 0.6;
|
||||
}
|
||||
@@ -2,6 +2,10 @@
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.margin-bottom-30 {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.margin-bottom-50 {
|
||||
margin-bottom: 50px;
|
||||
}
|
||||
|
||||
@@ -69,6 +69,21 @@ div#group_buy_calculation {
|
||||
text-indent:1em;
|
||||
}
|
||||
}
|
||||
|
||||
&.after {
|
||||
|
||||
span {
|
||||
position: absolute;
|
||||
transform: translate(0,-55%);
|
||||
top:50%;
|
||||
right: 0.5em;
|
||||
pointer-events:none;
|
||||
}
|
||||
|
||||
input {
|
||||
padding-right: 1.2em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
th.actions {
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
.select2-container {
|
||||
.select2-choice {
|
||||
.select2-search-choice-close {
|
||||
display: none;
|
||||
}
|
||||
.select2-arrow {
|
||||
width: 22px;
|
||||
border: none;
|
||||
@@ -7,4 +10,36 @@
|
||||
background-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
&.light {
|
||||
.select2-choice{
|
||||
background-color: #ffffff;
|
||||
font-weight: normal;
|
||||
border: 1px solid #5498da !important;
|
||||
color: #5498da !important;
|
||||
|
||||
.select2-arrow {
|
||||
&:before {
|
||||
color: #5498da;
|
||||
font-size: 1rem;
|
||||
font-weight: 400;
|
||||
content: '\25be';
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&:hover, &.select2-container-active {
|
||||
.select2-choice{
|
||||
color: #ffffff !important;
|
||||
background-color: #5498da !important;
|
||||
|
||||
.select2-arrow {
|
||||
&:before {
|
||||
color: #ffffff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
68
app/assets/stylesheets/admin/tag_rules.css.scss
Normal file
68
app/assets/stylesheets/admin/tag_rules.css.scss
Normal file
@@ -0,0 +1,68 @@
|
||||
.no_tags {
|
||||
margin-bottom: 40px;
|
||||
color: #aeaeae;
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.customer_tag {
|
||||
border: 1px solid #cee1f4;
|
||||
margin-bottom: 40px;
|
||||
|
||||
.header {
|
||||
padding: 8px 10px;
|
||||
background-color: #eff5fc;
|
||||
border-bottom: 1px solid #cee1f4;
|
||||
|
||||
table {
|
||||
padding: 0px;
|
||||
margin: 0px 0px 0px 0px;
|
||||
tr {
|
||||
td {
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.no_rules {
|
||||
padding: 8px 10px;
|
||||
margin-bottom: 10px;
|
||||
color: #aeaeae;
|
||||
font-size: 1rem;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
table {
|
||||
padding: 0px;
|
||||
margin: 0px 0px 10px 0px;
|
||||
|
||||
tr.tag_rule {
|
||||
border: none;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
|
||||
td {
|
||||
border: none;
|
||||
padding: 4px 10px 10px 10px;
|
||||
margin: 0px;
|
||||
|
||||
input {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.add_rule {
|
||||
padding: 8px 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
#new-tag-rule-dialog{
|
||||
.select2-chosen, .select2-result-label{
|
||||
font-size: 1rem;
|
||||
font-weight: lighter;
|
||||
}
|
||||
}
|
||||
@@ -7,3 +7,12 @@
|
||||
font-size: 1.2rem;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.text-red {
|
||||
color: #DA5354;
|
||||
}
|
||||
|
||||
|
||||
input.text-big {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ footer
|
||||
background-color: transparent
|
||||
border: none
|
||||
padding: 0
|
||||
a.big-alert
|
||||
a.alert-cta
|
||||
@include csstrans
|
||||
width: 100%
|
||||
border: 1px solid rgba($dark-grey, 0.35)
|
||||
|
||||
@@ -7,4 +7,7 @@
|
||||
@include sidepaddingSm
|
||||
|
||||
.name-matches, .distance-matches
|
||||
margin-top: 4em
|
||||
margin-top: 4em
|
||||
|
||||
.more-controls
|
||||
text-align: center
|
||||
|
||||
@@ -84,9 +84,11 @@
|
||||
padding-right: 0rem
|
||||
font-size: 0.8rem
|
||||
|
||||
.shopfront_message, .shopfront_closed_message
|
||||
.shopfront_message, .shopfront_closed_message, .shopfront_hidden_message
|
||||
padding: 15px
|
||||
border-radius: 5px
|
||||
|
||||
.shopfront_message, .shopfront_closed_message
|
||||
border: 2px solid #eb4c46
|
||||
|
||||
.shopfront_message
|
||||
@@ -94,3 +96,7 @@
|
||||
|
||||
.shopfront_closed_message
|
||||
margin: 2em 0em
|
||||
|
||||
.shopfront_hidden_message
|
||||
border: 2px solid #db4
|
||||
margin: 2em 0em
|
||||
|
||||
@@ -7,13 +7,25 @@ module Admin
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.json do
|
||||
render json: ActiveModel::ArraySerializer.new( @collection,
|
||||
each_serializer: Api::Admin::CustomerSerializer, spree_current_user: spree_current_user
|
||||
).to_json
|
||||
serialised = ActiveModel::ArraySerializer.new(
|
||||
@collection,
|
||||
each_serializer: Api::Admin::CustomerSerializer,
|
||||
spree_current_user: spree_current_user)
|
||||
render json: serialised.to_json
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
@customer = Customer.new(params[:customer])
|
||||
if user_can_create_customer?
|
||||
@customer.save
|
||||
render json: Api::Admin::CustomerSerializer.new(@customer).to_json
|
||||
else
|
||||
redirect_to '/unauthorized'
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def collection
|
||||
@@ -25,5 +37,10 @@ module Admin
|
||||
def load_managed_shops
|
||||
@shops = Enterprise.managed_by(spree_current_user).is_distributor
|
||||
end
|
||||
|
||||
def user_can_create_customer?
|
||||
spree_current_user.admin? ||
|
||||
spree_current_user.enterprises.include?(@customer.enterprise)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,7 +4,7 @@ module Admin
|
||||
class EnterprisesController < ResourceController
|
||||
before_filter :load_enterprise_set, :only => :index
|
||||
before_filter :load_countries, :except => [:index, :register, :check_permalink]
|
||||
before_filter :load_methods_and_fees, :only => [:new, :edit, :update, :create]
|
||||
before_filter :load_methods_and_fees, :only => [:edit, :update]
|
||||
before_filter :load_groups, :only => [:new, :edit, :update, :create]
|
||||
before_filter :load_taxons, :only => [:new, :edit, :update, :create]
|
||||
before_filter :check_can_change_sells, only: :update
|
||||
@@ -35,6 +35,8 @@ module Admin
|
||||
|
||||
def update
|
||||
invoke_callbacks(:update, :before)
|
||||
tag_rules_attributes = params[object_name].delete :tag_rules_attributes
|
||||
update_tag_rules(tag_rules_attributes) if tag_rules_attributes.present?
|
||||
if @object.update_attributes(params[object_name])
|
||||
invoke_callbacks(:update, :after)
|
||||
flash[:success] = flash_message_for(@object, :successfully_updated)
|
||||
@@ -180,6 +182,27 @@ module Admin
|
||||
@taxons = Spree::Taxon.order(:name)
|
||||
end
|
||||
|
||||
def update_tag_rules(tag_rules_attributes)
|
||||
# Due to the combination of trying to use nested attributes and type inheritance
|
||||
# we cannot apply all attributes to tag rules in one hit because mass assignment
|
||||
# methods that are specific to each class do not become available until after the
|
||||
# record is persisted. This problem is compounded by the use of calculators.
|
||||
@object.transaction do
|
||||
tag_rules_attributes.select{ |i, attrs| attrs[:type].present? }.each do |i, attrs|
|
||||
rule = @object.tag_rules.find_by_id(attrs.delete :id) || attrs[:type].constantize.new(enterprise: @object)
|
||||
create_calculator_for(rule, attrs) if rule.type == "TagRule::DiscountOrder" && rule.calculator.nil?
|
||||
rule.update_attributes(attrs)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create_calculator_for(rule, attrs)
|
||||
if attrs[:calculator_type].present? && attrs[:calculator_attributes].present?
|
||||
rule.update_attributes(calculator_type: attrs[:calculator_type])
|
||||
attrs[:calculator_attributes].merge!( { id: rule.calculator.id } )
|
||||
end
|
||||
end
|
||||
|
||||
def check_can_change_bulk_sells
|
||||
unless spree_current_user.admin?
|
||||
params[:enterprise_set][:collection_attributes].each do |i, enterprise_params|
|
||||
|
||||
10
app/controllers/admin/tag_rules_controller.rb
Normal file
10
app/controllers/admin/tag_rules_controller.rb
Normal file
@@ -0,0 +1,10 @@
|
||||
module Admin
|
||||
class TagRulesController < ResourceController
|
||||
|
||||
respond_to :json
|
||||
|
||||
respond_override destroy: { json: {
|
||||
success: lambda { render nothing: true, :status => 204 }
|
||||
} }
|
||||
end
|
||||
end
|
||||
17
app/controllers/api/statuses_controller.rb
Normal file
17
app/controllers/api/statuses_controller.rb
Normal file
@@ -0,0 +1,17 @@
|
||||
module Api
|
||||
class StatusesController < BaseController
|
||||
respond_to :json
|
||||
|
||||
def job_queue
|
||||
render json: {alive: job_queue_alive?}
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
def job_queue_alive?
|
||||
Spree::Config.last_job_queue_heartbeat_at.present? &&
|
||||
Time.parse(Spree::Config.last_job_queue_heartbeat_at) > 6.minutes.ago
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -20,11 +20,15 @@ module Admin
|
||||
end
|
||||
|
||||
def admin_inject_payment_methods
|
||||
admin_inject_json_ams_array "admin.payment_methods", "paymentMethods", @payment_methods, Api::Admin::IdNameSerializer
|
||||
admin_inject_json_ams_array "admin.paymentMethods", "paymentMethods", @payment_methods, Api::Admin::IdNameSerializer
|
||||
end
|
||||
|
||||
def admin_inject_shipping_methods
|
||||
admin_inject_json_ams_array "admin.shipping_methods", "shippingMethods", @shipping_methods, Api::Admin::IdNameSerializer
|
||||
admin_inject_json_ams_array "admin.shippingMethods", "shippingMethods", @shipping_methods, Api::Admin::IdNameSerializer
|
||||
end
|
||||
|
||||
def admin_inject_shipping_method
|
||||
admin_inject_json_ams "admin.shippingMethods", "shippingMethod", @shipping_method, Api::Admin::ShippingMethodSerializer
|
||||
end
|
||||
|
||||
def admin_inject_shops(ngModule='admin.customers')
|
||||
|
||||
@@ -4,7 +4,11 @@ module EnterprisesHelper
|
||||
end
|
||||
|
||||
def available_shipping_methods
|
||||
current_distributor.shipping_methods.uniq
|
||||
shipping_methods = current_distributor.shipping_methods
|
||||
if current_distributor.present?
|
||||
current_distributor.apply_tag_rules_to(shipping_methods, customer: current_order.customer)
|
||||
end
|
||||
shipping_methods.uniq
|
||||
end
|
||||
|
||||
def managed_enterprises
|
||||
|
||||
@@ -7,4 +7,16 @@ module ShopHelper
|
||||
]
|
||||
end
|
||||
end
|
||||
|
||||
def require_customer?
|
||||
current_distributor.require_login? && !user_is_related_to_distributor?
|
||||
end
|
||||
|
||||
def user_is_related_to_distributor?
|
||||
spree_current_user.present? && (
|
||||
spree_current_user.admin? ||
|
||||
spree_current_user.enterprises.include?(current_distributor) ||
|
||||
spree_current_user.customer_of(current_distributor)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -11,11 +11,17 @@ module Spree
|
||||
end
|
||||
|
||||
def report_payment_method_options(orders)
|
||||
orders.map { |o| o.payments.first.payment_method.andand.name }.uniq
|
||||
orders.map do |o|
|
||||
pm = o.payments.first.payment_method
|
||||
[pm.andand.name, pm.andand.id]
|
||||
end.uniq
|
||||
end
|
||||
|
||||
def report_shipping_method_options(orders)
|
||||
orders.map { |o| o.shipping_method.andand.name }.uniq
|
||||
orders.map do |o|
|
||||
sm = o.shipping_method
|
||||
[sm.andand.name, sm.andand.id]
|
||||
end.uniq
|
||||
end
|
||||
|
||||
def xero_report_types
|
||||
|
||||
5
app/jobs/heartbeat_job.rb
Normal file
5
app/jobs/heartbeat_job.rb
Normal file
@@ -0,0 +1,5 @@
|
||||
class HeartbeatJob
|
||||
def perform
|
||||
Spree::Config.last_job_queue_heartbeat_at = Time.now
|
||||
end
|
||||
end
|
||||
@@ -7,14 +7,14 @@ class ContentConfiguration < Spree::Preferences::FileConfiguration
|
||||
preference :logo, :file
|
||||
preference :logo_mobile, :file
|
||||
preference :logo_mobile_svg, :file
|
||||
has_attached_file :logo
|
||||
has_attached_file :logo, default_url: "/assets/ofn-logo.png"
|
||||
has_attached_file :logo_mobile
|
||||
has_attached_file :logo_mobile_svg
|
||||
has_attached_file :logo_mobile_svg, default_url: "/assets/ofn-logo-mobile.svg"
|
||||
|
||||
# Home page
|
||||
preference :home_hero, :file
|
||||
preference :home_show_stats, :boolean, default: true
|
||||
has_attached_file :home_hero
|
||||
has_attached_file :home_hero, default_url: "/assets/home/home.jpg"
|
||||
|
||||
# Producer sign-up page
|
||||
preference :producer_signup_pricing_table_html, :text, default: "(TODO: Pricing table)"
|
||||
@@ -33,7 +33,7 @@ class ContentConfiguration < Spree::Preferences::FileConfiguration
|
||||
|
||||
# Footer
|
||||
preference :footer_logo, :file
|
||||
has_attached_file :footer_logo
|
||||
has_attached_file :footer_logo, default_url: "/assets/ofn-logo-footer.png"
|
||||
preference :footer_facebook_url, :string, default: "https://www.facebook.com/OpenFoodNet"
|
||||
preference :footer_twitter_url, :string, default: "https://twitter.com/OpenFoodNet"
|
||||
preference :footer_instagram_url, :string, default: ""
|
||||
|
||||
@@ -4,6 +4,8 @@ class Customer < ActiveRecord::Base
|
||||
belongs_to :enterprise
|
||||
belongs_to :user, class_name: Spree.user_class
|
||||
|
||||
before_validation :downcase_email
|
||||
|
||||
validates :code, uniqueness: { scope: :enterprise_id, allow_blank: true, allow_nil: true }
|
||||
validates :email, presence: true, uniqueness: { scope: :enterprise_id, message: I18n.t('validation_msg_is_associated_with_an_exising_customer') }
|
||||
validates :enterprise_id, presence: true
|
||||
@@ -14,6 +16,10 @@ class Customer < ActiveRecord::Base
|
||||
|
||||
private
|
||||
|
||||
def downcase_email
|
||||
email.andand.downcase!
|
||||
end
|
||||
|
||||
def associate_user
|
||||
self.user = user || Spree::User.find_by_email(email)
|
||||
end
|
||||
|
||||
@@ -42,11 +42,13 @@ class Enterprise < ActiveRecord::Base
|
||||
has_many :customers
|
||||
has_many :billable_periods
|
||||
has_many :inventory_items
|
||||
has_many :tag_rules
|
||||
|
||||
delegate :latitude, :longitude, :city, :state_name, :to => :address
|
||||
|
||||
accepts_nested_attributes_for :address
|
||||
accepts_nested_attributes_for :producer_properties, allow_destroy: true, reject_if: lambda { |pp| pp[:property_name].blank? }
|
||||
accepts_nested_attributes_for :tag_rules, allow_destroy: true, reject_if: lambda { |tag_rule| tag_rule[:preferred_customer_tags].blank? }
|
||||
|
||||
has_attached_file :logo,
|
||||
styles: { medium: "300x300>", small: "180x180>", thumb: "100x100>" },
|
||||
@@ -176,17 +178,6 @@ class Enterprise < ActiveRecord::Base
|
||||
end
|
||||
}
|
||||
|
||||
def self.find_near(suburb)
|
||||
enterprises = []
|
||||
|
||||
unless suburb.nil?
|
||||
addresses = Spree::Address.near([suburb.latitude, suburb.longitude], ENTERPRISE_SEARCH_RADIUS, :units => :km).joins(:enterprise).limit(10)
|
||||
enterprises = addresses.collect(&:enterprise)
|
||||
end
|
||||
|
||||
enterprises
|
||||
end
|
||||
|
||||
# Force a distinct count to work around relation count issue https://github.com/rails/rails/issues/5554
|
||||
def self.distinct_count
|
||||
count(distinct: true)
|
||||
@@ -354,6 +345,13 @@ class Enterprise < ActiveRecord::Base
|
||||
abn.present?
|
||||
end
|
||||
|
||||
def apply_tag_rules_to(subject, context)
|
||||
tag_rules.each do |rule|
|
||||
rule.set_context(subject,context)
|
||||
rule.apply
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def devise_mailer
|
||||
|
||||
@@ -72,6 +72,10 @@ class AbilityDecorator
|
||||
|
||||
can [:admin, :index, :read, :create, :edit, :update_positions, :destroy], ProducerProperty
|
||||
|
||||
can [:admin, :destroy], TagRule do |tag_rule|
|
||||
user.enterprises.include? tag_rule.enterprise
|
||||
end
|
||||
|
||||
can [:admin, :index, :create], Enterprise
|
||||
can [:read, :edit, :update, :bulk_update, :resend_confirmation], Enterprise do |enterprise|
|
||||
OpenFoodNetwork::Permissions.new(user).editable_enterprises.include? enterprise
|
||||
@@ -97,6 +101,11 @@ class AbilityDecorator
|
||||
can [:print], Spree::Order do |order|
|
||||
order.user == user
|
||||
end
|
||||
|
||||
can [:create], Customer
|
||||
can [:destroy], Customer do |customer|
|
||||
user.enterprises.include? customer.enterprise
|
||||
end
|
||||
end
|
||||
|
||||
def add_product_management_abilities(user)
|
||||
|
||||
@@ -20,4 +20,7 @@ Spree::AppConfiguration.class_eval do
|
||||
preference :account_invoices_monthly_rate, :decimal, default: 0
|
||||
preference :account_invoices_monthly_cap, :decimal, default: 0
|
||||
preference :account_invoices_tax_rate, :decimal, default: 0
|
||||
|
||||
# Monitoring
|
||||
preference :last_job_queue_heartbeat_at, :string, default: nil
|
||||
end
|
||||
|
||||
@@ -17,7 +17,8 @@ Spree::Order.class_eval do
|
||||
attr_accessible :order_cycle_id, :distributor_id
|
||||
|
||||
before_validation :shipping_address_from_distributor
|
||||
before_validation :associate_customer, unless: :customer_is_valid?
|
||||
before_validation :associate_customer, unless: :customer_id?
|
||||
before_validation :ensure_customer, unless: :customer_is_valid?
|
||||
|
||||
checkout_flow do
|
||||
go_to_state :address
|
||||
@@ -69,13 +70,6 @@ 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 IN (?)', payment_method_name).
|
||||
select('DISTINCT spree_orders.*')
|
||||
}
|
||||
|
||||
|
||||
# -- Methods
|
||||
def products_available_from_new_distribution
|
||||
# Check that the line_items in the current order are available from a newly selected distribution
|
||||
@@ -179,6 +173,10 @@ Spree::Order.class_eval do
|
||||
if order_cycle
|
||||
OpenFoodNetwork::EnterpriseFeeCalculator.new.create_order_adjustments_for self
|
||||
end
|
||||
|
||||
if distributor.present? && customer.present?
|
||||
distributor.apply_tag_rules_to(self, customer: customer)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -286,17 +284,21 @@ Spree::Order.class_eval do
|
||||
|
||||
def customer_is_valid?
|
||||
return true unless require_customer?
|
||||
customer.present? && customer.enterprise_id == distributor_id && customer.email == (user.andand.email || email)
|
||||
customer.present? && customer.enterprise_id == distributor_id && customer.email == email_for_customer
|
||||
end
|
||||
|
||||
def email_for_customer
|
||||
(user.andand.email || email).andand.downcase
|
||||
end
|
||||
|
||||
def associate_customer
|
||||
email_for_customer = user.andand.email || email
|
||||
existing_customer = Customer.of(distributor).find_by_email(email_for_customer)
|
||||
if existing_customer
|
||||
self.customer = existing_customer
|
||||
else
|
||||
new_customer = Customer.create(enterprise: distributor, email: email_for_customer, user: user)
|
||||
self.customer = new_customer
|
||||
return customer if customer.present?
|
||||
self.customer = Customer.of(distributor).find_by_email(email_for_customer)
|
||||
end
|
||||
|
||||
def ensure_customer
|
||||
unless associate_customer
|
||||
self.customer = Customer.create(enterprise: distributor, email: email_for_customer, user: user)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
Spree::ShippingMethod.class_eval do
|
||||
acts_as_taggable
|
||||
|
||||
has_many :distributor_shipping_methods
|
||||
has_many :distributors, through: :distributor_shipping_methods, class_name: 'Enterprise', foreign_key: 'distributor_id'
|
||||
|
||||
after_save :touch_distributors
|
||||
attr_accessible :distributor_ids, :description
|
||||
attr_accessible :require_ship_address
|
||||
attr_accessible :require_ship_address, :tag_list
|
||||
|
||||
validates :distributors, presence: { message: "^At least one hub must be selected" }
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ Spree.user_class.class_eval do
|
||||
accepts_nested_attributes_for :enterprise_roles, :allow_destroy => true
|
||||
|
||||
attr_accessible :enterprise_ids, :enterprise_roles_attributes, :enterprise_limit
|
||||
after_create :associate_customers
|
||||
after_create :send_signup_confirmation
|
||||
|
||||
validate :limit_owned_enterprises
|
||||
@@ -41,6 +42,10 @@ Spree.user_class.class_eval do
|
||||
customers.of(enterprise).first
|
||||
end
|
||||
|
||||
def associate_customers
|
||||
Customer.update_all({ user_id: id }, { user_id: nil, email: email })
|
||||
end
|
||||
|
||||
def send_signup_confirmation
|
||||
Delayed::Job.enqueue ConfirmSignupJob.new(id)
|
||||
end
|
||||
|
||||
42
app/models/tag_rule.rb
Normal file
42
app/models/tag_rule.rb
Normal file
@@ -0,0 +1,42 @@
|
||||
class TagRule < ActiveRecord::Base
|
||||
attr_accessor :subject, :context
|
||||
|
||||
belongs_to :enterprise
|
||||
|
||||
preference :customer_tags, :string, default: ""
|
||||
|
||||
validates :enterprise, presence: true
|
||||
|
||||
attr_accessible :enterprise, :enterprise_id, :preferred_customer_tags
|
||||
|
||||
def set_context(subject, context)
|
||||
@subject = subject
|
||||
@context = context
|
||||
end
|
||||
|
||||
def apply
|
||||
if relevant?
|
||||
if customer_tags_match?
|
||||
apply!
|
||||
else
|
||||
apply_default! if respond_to?(:apply_default!,true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def relevant?
|
||||
return false unless subject_class_matches?
|
||||
if respond_to?(:additional_requirements_met?, true)
|
||||
return false unless additional_requirements_met?
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
def customer_tags_match?
|
||||
context_customer_tags = context.andand[:customer].andand.tag_list || []
|
||||
preferred_tags = preferred_customer_tags.split(",")
|
||||
( context_customer_tags & preferred_tags ).any?
|
||||
end
|
||||
end
|
||||
23
app/models/tag_rule/discount_order.rb
Normal file
23
app/models/tag_rule/discount_order.rb
Normal file
@@ -0,0 +1,23 @@
|
||||
class TagRule::DiscountOrder < TagRule
|
||||
calculated_adjustments
|
||||
|
||||
private
|
||||
|
||||
# Warning: this should only EVER be called via TagRule#apply
|
||||
def apply!
|
||||
create_adjustment(I18n.t("discount"), subject, subject)
|
||||
end
|
||||
|
||||
def subject_class_matches?
|
||||
subject.class == Spree::Order
|
||||
end
|
||||
|
||||
def additional_requirements_met?
|
||||
return false if already_applied?
|
||||
true
|
||||
end
|
||||
|
||||
def already_applied?
|
||||
subject.adjustments.where(originator_id: id, originator_type: "TagRule").any?
|
||||
end
|
||||
end
|
||||
32
app/models/tag_rule/filter_shipping_methods.rb
Normal file
32
app/models/tag_rule/filter_shipping_methods.rb
Normal file
@@ -0,0 +1,32 @@
|
||||
class TagRule::FilterShippingMethods < TagRule
|
||||
preference :matched_shipping_methods_visibility, :string, default: "visible"
|
||||
preference :shipping_method_tags, :string, default: ""
|
||||
|
||||
attr_accessible :preferred_matched_shipping_methods_visibility, :preferred_shipping_method_tags
|
||||
|
||||
private
|
||||
|
||||
# Warning: this should only EVER be called via TagRule#apply
|
||||
def apply!
|
||||
unless preferred_matched_shipping_methods_visibility == "visible"
|
||||
subject.reject!{ |sm| tags_match?(sm) }
|
||||
end
|
||||
end
|
||||
|
||||
def apply_default!
|
||||
if preferred_matched_shipping_methods_visibility == "visible"
|
||||
subject.reject!{ |sm| tags_match?(sm) }
|
||||
end
|
||||
end
|
||||
|
||||
def tags_match?(shipping_method)
|
||||
shipping_method_tags = shipping_method.andand.tag_list || []
|
||||
preferred_tags = preferred_shipping_method_tags.split(",")
|
||||
( shipping_method_tags & preferred_tags ).any?
|
||||
end
|
||||
|
||||
def subject_class_matches?
|
||||
subject.class == Array &&
|
||||
subject.all? { |i| i.class == Spree::ShippingMethod }
|
||||
end
|
||||
end
|
||||
@@ -1,4 +1,4 @@
|
||||
// insert_bottom "[data-hook='admin_configurations_sidebar_menu']"
|
||||
|
||||
%li
|
||||
= link_to 'Accounts & Billing', main_app.edit_admin_accounts_and_billing_settings_path
|
||||
= link_to t(:accounts_and_billing), main_app.edit_admin_accounts_and_billing_settings_path
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
/ replace "div[data-hook='admin_shipping_method_form_fields']"
|
||||
|
||||
.alpha.eleven.columns{"data-hook" => "admin_shipping_method_form_fields"}
|
||||
=admin_inject_shipping_method
|
||||
.alpha.eleven.columns{ "data-hook" => "admin_shipping_method_form_fields",
|
||||
"ng-app" => "admin.shippingMethods",
|
||||
"ng-controller" => "shippingMethodCtrl" }
|
||||
.row
|
||||
.alpha.three.columns
|
||||
= f.label :name, t(:name)
|
||||
@@ -46,6 +49,13 @@
|
||||
|
||||
= f.label :pick_up, t(:pick_up)
|
||||
|
||||
.row
|
||||
.alpha.three.columns
|
||||
= f.label :tags, t(:tags)
|
||||
.omega.eight.columns
|
||||
= f.hidden_field :tag_list, "ng-value" => "shippingMethod.tag_list"
|
||||
%tags-with-translation#something{ object: "shippingMethod" }
|
||||
|
||||
.row
|
||||
.alpha.eleven.columns
|
||||
= render :partial => 'spree/admin/shared/calculator_fields', :locals => { :f => f }
|
||||
= render :partial => 'spree/admin/shared/calculator_fields', :locals => { :f => f }
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
class Api::Admin::Calculator::FlatPercentItemTotalSerializer < ActiveModel::Serializer
|
||||
attributes :id, :preferred_flat_percent
|
||||
|
||||
def preferred_flat_percent
|
||||
object.preferred_flat_percent.to_i
|
||||
end
|
||||
end
|
||||
@@ -3,8 +3,25 @@ class Api::Admin::EnterpriseSerializer < ActiveModel::Serializer
|
||||
attributes :producer_profile_only, :email, :long_description, :permalink
|
||||
attributes :preferred_shopfront_message, :preferred_shopfront_closed_message, :preferred_shopfront_taxon_order, :preferred_shopfront_order_cycle_order
|
||||
attributes :preferred_product_selection_from_inventory_only
|
||||
attributes :owner, :users
|
||||
attributes :owner, :users, :tag_groups
|
||||
|
||||
has_one :owner, serializer: Api::Admin::UserSerializer
|
||||
has_many :users, serializer: Api::Admin::UserSerializer
|
||||
|
||||
def tag_groups
|
||||
tag_groups = []
|
||||
object.tag_rules.each do |tag_rule|
|
||||
tag_group = find_match(tag_groups, tag_rule.preferred_customer_tags.split(",").map{ |t| { text: t } })
|
||||
tag_groups << tag_group if tag_group[:rules].empty?
|
||||
tag_group[:rules] << Api::Admin::TagRuleSerializer.new(tag_rule).serializable_hash
|
||||
end
|
||||
tag_groups
|
||||
end
|
||||
|
||||
def find_match(tag_groups, tags)
|
||||
tag_groups.each do |tag_group|
|
||||
return tag_group if tag_group[:tags].length == tags.length && (tag_group[:tags] & tags) == tag_group[:tags]
|
||||
end
|
||||
return { tags: tags, rules: [] }
|
||||
end
|
||||
end
|
||||
|
||||
7
app/serializers/api/admin/shipping_method_serializer.rb
Normal file
7
app/serializers/api/admin/shipping_method_serializer.rb
Normal file
@@ -0,0 +1,7 @@
|
||||
class Api::Admin::ShippingMethodSerializer < ActiveModel::Serializer
|
||||
attributes :id, :name, :tags
|
||||
|
||||
def tags
|
||||
object.tag_list.map{ |t| { text: t } }
|
||||
end
|
||||
end
|
||||
27
app/serializers/api/admin/tag_rule_serializer.rb
Normal file
27
app/serializers/api/admin/tag_rule_serializer.rb
Normal file
@@ -0,0 +1,27 @@
|
||||
class Api::Admin::TagRuleSerializer < ActiveModel::Serializer
|
||||
def serializable_hash
|
||||
rule_specific_serializer.serializable_hash
|
||||
end
|
||||
|
||||
def rule_specific_serializer
|
||||
"Api::Admin::#{object.class.to_s}Serializer".constantize.new(object)
|
||||
end
|
||||
end
|
||||
|
||||
module Api::Admin::TagRule
|
||||
class BaseSerializer < ActiveModel::Serializer
|
||||
attributes :id, :enterprise_id, :type, :preferred_customer_tags
|
||||
end
|
||||
|
||||
class DiscountOrderSerializer < BaseSerializer
|
||||
has_one :calculator, serializer: Api::Admin::Calculator::FlatPercentItemTotalSerializer
|
||||
end
|
||||
|
||||
class FilterShippingMethodsSerializer < BaseSerializer
|
||||
attributes :preferred_matched_shipping_methods_visibility, :shipping_method_tags
|
||||
|
||||
def shipping_method_tags
|
||||
object.preferred_shipping_method_tags.split(",")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,7 +1,7 @@
|
||||
= render :partial => 'spree/admin/shared/configuration_menu'
|
||||
|
||||
- content_for :page_title do
|
||||
= t(:accounts_and_billing_settings)
|
||||
= t(:accounts_and_billing)
|
||||
|
||||
= render 'spree/shared/error_messages', target: @settings
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
%legend
|
||||
=t :admin_settings
|
||||
= form_for @settings, as: :settings, url: main_app.admin_accounts_and_billing_settings_path, :method => :put do |f|
|
||||
.row{ ng: { app: t(:admin_accounts_and_billing) } }
|
||||
.row{ ng: { app: 'admin.accounts_and_billing_settings' } }
|
||||
.twelve.columns.alpha.omega
|
||||
.field
|
||||
= f.label :accounts_distributor_id, t(:accounts_administration_distributor)
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
= admin_inject_shops
|
||||
|
||||
%div{ ng: { app: 'admin.customers', controller: 'customersCtrl' } }
|
||||
.row{ ng: { hide: "loaded() && filteredCustomers.length > 0" } }
|
||||
.row{ ng: { hide: "loaded && customers.length > 0" } }
|
||||
.five.columns.alpha
|
||||
%h3
|
||||
=t :please_select_hub
|
||||
@@ -13,25 +13,23 @@
|
||||
%select.select2.fullwidth#shop_id{ 'ng-model' => 'shop.id', name: 'shop_id', 'ng-options' => 'shop.id as shop.name for shop in shops' }
|
||||
.seven.columns.omega
|
||||
|
||||
.row{ 'ng-hide' => '!loaded() || filteredCustomers.length == 0' }
|
||||
.row{ 'ng-hide' => '!loaded || customers.length == 0' }
|
||||
.controls.sixteen.columns.alpha.omega
|
||||
.five.columns.alpha
|
||||
%input.fullwidth{ :type => "text", :id => 'quick_search', 'ng-model' => 'quickSearch', :placeholder => 'Quick Search' }
|
||||
.five.columns
|
||||
-# =render 'admin/shared/bulk_actions_dropdown'
|
||||
.three.columns
|
||||
.eight.columns
|
||||
= render 'admin/shared/columns_dropdown'
|
||||
.row{ 'ng-if' => 'shop && !loaded()' }
|
||||
.row{ 'ng-if' => 'shop.id && !loaded' }
|
||||
.sixteen.columns.alpha#loading
|
||||
%img.spinner{ src: "/assets/spinning-circles.svg" }
|
||||
%h1
|
||||
=t :loading_customers
|
||||
.row{ :class => "sixteen columns alpha", 'ng-show' => 'loaded() && filteredCustomers.length == 0'}
|
||||
.row{ :class => "sixteen columns alpha", 'ng-show' => 'loaded && filteredCustomers.length == 0'}
|
||||
%h1#no_results
|
||||
=t :no_customers_found
|
||||
|
||||
|
||||
.row{ ng: { show: "loaded() && filteredCustomers.length > 0" } }
|
||||
.row{ ng: { show: "loaded && filteredCustomers.length > 0" } }
|
||||
%form{ name: "customers" }
|
||||
%table.index#customers
|
||||
%col.email{ width: "20%"}
|
||||
@@ -62,3 +60,11 @@
|
||||
%td.actions
|
||||
%a{ 'ng-click' => "deleteCustomer(customer)", :class => "delete-customer icon-trash no-text" }
|
||||
%input{ :type => "button", 'value' => 'Update', 'ng-click' => 'submitAll()' }
|
||||
|
||||
%form{ng: {show: "loaded", submit: 'add(newCustomerEmail)'}}
|
||||
%h2= t '.add_new_customer'
|
||||
.row
|
||||
.five.columns.alpha
|
||||
%input.fullwidth{type: "text", placeholder: t('.customer_placeholder'), ng: {model: 'newCustomerEmail'}}
|
||||
.eleven.columns.omega
|
||||
%input{type: "submit", value: t('.add_customer')}
|
||||
|
||||
@@ -54,3 +54,7 @@
|
||||
%fieldset.alpha.no-border-bottom{ ng: { show: "menu.selected.name=='Shop Preferences'" } }
|
||||
%legend Shop Preferences
|
||||
= render 'admin/enterprises/form/shop_preferences', f: f
|
||||
|
||||
%fieldset.alpha.no-border-bottom{ ng: { if: "menu.selected.name=='Tag Rules'" } }
|
||||
%legend Tag Rules
|
||||
= render 'admin/enterprises/form/tag_rules', f: f
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
- content_for :page_actions do
|
||||
%li= button_link_to "Back to enterprises list", main_app.admin_enterprises_path, icon: 'icon-arrow-left'
|
||||
|
||||
|
||||
= render 'admin/enterprises/form_data'
|
||||
|
||||
= render 'admin/enterprises/ng_form', action: 'edit'
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
%a What's this?
|
||||
.five.columns.omega
|
||||
= f.check_box :is_primary_producer, 'ng-model' => 'Enterprise.is_primary_producer'
|
||||
|
||||
= f.label :is_primary_producer, 'Producer'
|
||||
- if spree_current_user.admin?
|
||||
.row
|
||||
@@ -33,15 +32,12 @@
|
||||
%a What's this?
|
||||
.two.columns
|
||||
= f.radio_button :sells, "none", 'ng-model' => 'Enterprise.sells'
|
||||
|
||||
= f.label :sells, "None", value: "none"
|
||||
.two.columns
|
||||
= f.radio_button :sells, "own", 'ng-model' => 'Enterprise.sells'
|
||||
|
||||
= f.label :sells, "Own", value: "own"
|
||||
.four.columns.omega
|
||||
= f.radio_button :sells, "any", 'ng-model' => 'Enterprise.sells'
|
||||
|
||||
= f.label :sells, "Any", value: "any"
|
||||
.row
|
||||
.three.columns.alpha
|
||||
@@ -50,12 +46,21 @@
|
||||
%a What's this?
|
||||
.two.columns
|
||||
= f.radio_button :visible, true
|
||||
|
||||
= f.label :visible, "Visible", :value => "true"
|
||||
.five.columns.omega
|
||||
= f.radio_button :visible, false
|
||||
|
||||
= f.label :visible, "Not Visible", :value => "false"
|
||||
.row
|
||||
.three.columns.alpha
|
||||
%label= t '.shopfront_requires_login'
|
||||
%div{'ofn-with-tip' => t('.shopfront_requires_login_tip')}
|
||||
%a= t 'admin.whats_this'
|
||||
.two.columns
|
||||
= f.radio_button :require_login, false
|
||||
= f.label :require_login, t('.shopfront_requires_login_false'), value: :false
|
||||
.five.columns.omega
|
||||
= f.radio_button :require_login, true
|
||||
= f.label :require_login, t('.shopfront_requires_login_true'), value: :true
|
||||
.permalink{ ng: { controller: "permalinkCtrl" } }
|
||||
.row{ ng: { show: "Enterprise.sells == 'own' || Enterprise.sells == 'any'" } }
|
||||
.three.columns.alpha
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
%th
|
||||
%tbody
|
||||
- @shipping_methods.each do |shipping_method|
|
||||
%tr{ ng: { controller: 'shippingMethodCtrl', init: "findShippingMethodByID(#{shipping_method.id})" } }
|
||||
%tr{ ng: { controller: 'shippingMethodsCtrl', init: "findShippingMethodByID(#{shipping_method.id})" } }
|
||||
%td= shipping_method.name
|
||||
%td= f.check_box :shipping_method_ids, { :multiple => true, 'ng-model' => 'ShippingMethod.selected' }, shipping_method.id, nil
|
||||
%td= link_to "Edit", edit_admin_shipping_method_path(shipping_method)
|
||||
|
||||
33
app/views/admin/enterprises/form/_tag_rules.html.haml
Normal file
33
app/views/admin/enterprises/form/_tag_rules.html.haml
Normal file
@@ -0,0 +1,33 @@
|
||||
.row{ ng: { controller: "TagRulesCtrl" } }
|
||||
.eleven.columns.alpha.omega
|
||||
.eleven.columns.alpha.omega
|
||||
.no_tags{ ng: { show: "tagGroups.length == 0" } }
|
||||
No tags apply to this enterprise yet
|
||||
.customer_tag{ ng: { repeat: "tagGroup in tagGroups" }, bindonce: true }
|
||||
.header
|
||||
%table
|
||||
%colgroup
|
||||
%col{width: '35%'}
|
||||
%col{width: '65%'}
|
||||
%tr
|
||||
%td
|
||||
%h5
|
||||
For customers tagged:
|
||||
%td
|
||||
%tags-input{ ng: { model: 'tagGroup.tags'},
|
||||
min: { tags: "1" },
|
||||
on: { tag: { added: "updateTagsRulesFor(tagGroup)", removed: "updateTagsRulesFor(tagGroup)" } } }
|
||||
|
||||
.no_rules{ ng: { show: "tagGroup.rules.length == 0" } }
|
||||
No rules apply to this tag yet
|
||||
%table
|
||||
%tr.tag_rule{ id: "tr_{{rule.id}}", ng: { repeat: "rule in tagGroup.rules" } }
|
||||
%td
|
||||
%discount-order{ bo: { if: "rule.type == 'TagRule::DiscountOrder'" } }
|
||||
%filter-shipping-methods{ bo: { if: "rule.type == 'TagRule::FilterShippingMethods'" } }
|
||||
%td.actions
|
||||
%a{ ng: { click: "deleteTagRule(tagGroup, rule)" }, :class => "delete-tag-rule icon-trash no-text" }
|
||||
.add_rule.text-center
|
||||
%input.button.icon-plus{ type: 'button', value: "+ Add A New Rule", "new-tag-rule-dialog" => true }
|
||||
.add_tage
|
||||
%input.button.red.icon-plus{ type: 'button', value: "+ Add A New Tag", ng: { click: 'addNewTag()' } }
|
||||
@@ -1,4 +1,4 @@
|
||||
.filters.sixteen.columns.alpha
|
||||
.filters.sixteen.columns.alpha.omega
|
||||
.filter.four.columns.alpha
|
||||
%label{ :for => 'query', ng: {class: '{disabled: !hub_id}'} }=t('admin.quick_search')
|
||||
%br
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.sixteen.columns.alpha.omega.text-center{ ng: {show: 'productLimit < filteredProducts.length'}}
|
||||
.text-center
|
||||
%input{ type: 'button', value: 'Show More', ng: { click: 'productLimit = productLimit + 10' } }
|
||||
or
|
||||
%input{ type: 'button', value: "Show All ({{ filteredProducts.length - productLimit }} More)", ng: { click: 'productLimit = filteredProducts.length' } }
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
%section{"ng-show" => "!enabled"}
|
||||
.row
|
||||
.small-12.columns.text-center{"ng-controller" => "AuthenticationCtrl"}
|
||||
.small-12.columns.text-center
|
||||
%h3.pad-top
|
||||
= t :checkout_headline
|
||||
.row.pad-top
|
||||
.small-5.columns.text-center{"ng-controller" => "AuthenticationCtrl"}
|
||||
%button.primary.expand{"ng-click" => "open()"}
|
||||
.small-5.columns.text-center
|
||||
%button.primary.expand{"auth" => "login"}
|
||||
= t :label_login
|
||||
.small-2.columns.text-center
|
||||
%p.pad-top= "-#{t :action_or}-"
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
%select.avenir#order_cycle_id{"ng-model" => "order_cycle.order_cycle_id",
|
||||
"ofn-change-order-cycle" => true,
|
||||
"disabled" => require_customer?,
|
||||
"ng-options" => "oc.id as oc.time for oc in #{@order_cycles.map {|oc| {time: pickup_time(oc), id: oc.id}}.to_json}",
|
||||
"popover-placement" => "left", "popover" => t(:enterprises_choose), "popover-trigger" => "openTrigger"}
|
||||
|
||||
@@ -31,7 +32,7 @@
|
||||
|
||||
= render partial: 'shop/messages'
|
||||
|
||||
.row
|
||||
= render partial: "shop/products/form"
|
||||
- unless require_customer?
|
||||
.row= render partial: "shop/products/form"
|
||||
|
||||
= render partial: "shared/footer"
|
||||
|
||||
@@ -27,3 +27,9 @@
|
||||
.show-distance-matches{"ng-show" => "nameMatchesFiltered.length > 0 && !distanceMatchesShown"}
|
||||
%a{href: "", "ng-click" => "showDistanceMatches()"}
|
||||
= t :hubs_distance_filter, location: "{{ nameMatchesFiltered[0].name }}"
|
||||
.more-controls
|
||||
%a.button{href: "", ng: {click: "showClosedShops()", show: "filterExpression.active"}}
|
||||
= t '.show_closed_shops'
|
||||
%a.button{href: "", ng: {click: "hideClosedShops()", show: "!filterExpression.active"}}
|
||||
= t '.hide_closed_shops'
|
||||
%a.button{href: main_app.map_path}= t '.show_on_map'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.active_table
|
||||
%hub.active_table_node.row{"ng-repeat" => "hub in #{enterprises}Filtered = (#{enterprises} | visible | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles | orderBy:['-active', '+distance', '+orders_close_at'])",
|
||||
%hub.active_table_node.row{"ng-repeat" => "hub in #{enterprises}Filtered = (#{enterprises} | filter:filterExpression | taxons:activeTaxons | shipping:shippingTypes | showHubProfiles:show_profiles | orderBy:['-active', '+distance', '+orders_close_at'])",
|
||||
"ng-class" => "{'is_profile' : hub.category == 'hub_profile', 'closed' : !open(), 'open' : open(), 'inactive' : !hub.active, 'current' : current()}",
|
||||
"ng-controller" => "HubNodeCtrl",
|
||||
id: "{{hub.hash}}"}
|
||||
|
||||
@@ -7,13 +7,7 @@
|
||||
.row
|
||||
.small-12.medium-8.medium-offset-2.columns.text-center
|
||||
.alert-box
|
||||
%a.big-alert{href: "http://www.openfoodnetwork.org", target: "_blank"}
|
||||
%h6
|
||||
= t :alert_selling_on_ofn
|
||||
|
||||
%strong
|
||||
= t :alert_start_here
|
||||
%i.ofn-i_054-point-right
|
||||
= render 'shared/register_call'
|
||||
.row
|
||||
.small-12.medium-4.medium-offset-2.columns.text-center
|
||||
%h6
|
||||
|
||||
7
app/views/shared/_register_call.html.haml
Normal file
7
app/views/shared/_register_call.html.haml
Normal file
@@ -0,0 +1,7 @@
|
||||
%a.alert-cta{href: registration_path, target: "_blank"}
|
||||
%h6
|
||||
= t '.selling_on_ofn'
|
||||
|
||||
%strong
|
||||
= t '.register'
|
||||
%i.ofn-i_054-point-right
|
||||
@@ -1,5 +1,5 @@
|
||||
%li#login-link{"ng-controller" => "AuthenticationCtrl"}
|
||||
%a{"ng-click" => "open()"}
|
||||
%li#login-link
|
||||
%a{"auth" => "login"}
|
||||
%i.ofn-i_017-locked
|
||||
%span
|
||||
= t 'label_login'
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
.text-center.page-alert.fixed{ "ofn-page-alert" => true }
|
||||
.alert-box
|
||||
%a.alert-cta{href: registration_path, target: "_blank"}
|
||||
%h6
|
||||
= t 'alert_selling_on_ofn'
|
||||
|
||||
%strong
|
||||
= t 'alert_start_here'
|
||||
%i.ofn-i_054-point-right
|
||||
= render 'shared/register_call'
|
||||
%a.close{ ng: { click: "close()" } } ×
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
|
||||
- if @order_cycles and @order_cycles.empty?
|
||||
- if require_customer?
|
||||
.row.footer-pad
|
||||
.small-12.columns
|
||||
.shopfront_hidden_message
|
||||
= t '.require_customer_login'
|
||||
- if spree_current_user.nil?
|
||||
= t '.require_login_html',
|
||||
{login: ('<a auth="login">' + t('.login') + '</a>').html_safe,
|
||||
register: ('<a auth="signup">' + t('.register') + '</a>').html_safe}
|
||||
- else
|
||||
= t '.require_customer_html',
|
||||
{contact: ('<a href="##contact">' + t('.contact') + '</a>').html_safe,
|
||||
enterprise: current_distributor.name}
|
||||
- elsif @order_cycles and @order_cycles.empty?
|
||||
- if current_distributor.preferred_shopfront_closed_message.present?
|
||||
.row
|
||||
.small-12.columns
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
%br
|
||||
%table#listing_customers.index
|
||||
%thead
|
||||
%tr{'data-hook' => "orders_header" }
|
||||
%tr{'data-hook' => "orders_header"}
|
||||
- @report.header.each do |heading|
|
||||
%th=heading
|
||||
%tbody
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
%br
|
||||
%table#listing_ocm_orders.index
|
||||
%thead
|
||||
%tr{'data-hook' => "orders_header" }
|
||||
%tr{'data-hook' => "orders_header"}
|
||||
- @report.header.each do |heading|
|
||||
%th=heading
|
||||
%tbody
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
%br
|
||||
%table#listing_orders.index
|
||||
%thead
|
||||
%tr{'data-hook' => t(:report_customers_header)}
|
||||
%tr{'data-hook' => 'orders_header'}
|
||||
- @report.header.each do |heading|
|
||||
%th=heading
|
||||
%tbody
|
||||
@@ -21,4 +21,3 @@
|
||||
- if @report.table.empty?
|
||||
%tr
|
||||
%td{:colspan => "2"}= t(:none)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
- if enterprise
|
||||
-if shop_trial_in_progress?(enterprise)
|
||||
#trial_progress_bar
|
||||
= t(:shop_trial_in_progress)
|
||||
= t(:shop_trial_in_progress, days: remaining_trial_days(enterprise))
|
||||
-elsif shop_trial_expired?(enterprise)
|
||||
#trial_progress_bar
|
||||
= t(:shop_trial_expired)
|
||||
= t(:shop_trial_expired)
|
||||
|
||||
1
config/initializers/acts_as_taggable_on.rb
Normal file
1
config/initializers/acts_as_taggable_on.rb
Normal file
@@ -0,0 +1 @@
|
||||
ActsAsTaggableOn.force_lowercase = true
|
||||
@@ -10,6 +10,12 @@ en-GB:
|
||||
password:
|
||||
confirmation: you have successfully registered
|
||||
too_short: pick a longer name
|
||||
# Overridden here due to a bug in spree i18n (Issue #870)
|
||||
attributes:
|
||||
spree/order:
|
||||
payment_state: Payment State
|
||||
shipment_state: Shipment State
|
||||
|
||||
devise:
|
||||
failure:
|
||||
invalid: |
|
||||
|
||||
@@ -15,6 +15,12 @@
|
||||
# See http://community.openfoodnetwork.org/t/localisation-ofn-in-your-language/397
|
||||
|
||||
en:
|
||||
activerecord:
|
||||
# Overridden here due to a bug in spree i18n (Issue #870)
|
||||
attributes:
|
||||
spree/order:
|
||||
payment_state: Payment State
|
||||
shipment_state: Shipment State
|
||||
devise:
|
||||
failure:
|
||||
invalid: |
|
||||
@@ -74,6 +80,10 @@ en:
|
||||
|
||||
whats_this: What's this?
|
||||
|
||||
customers:
|
||||
index:
|
||||
add_customer: "Add customer"
|
||||
customer_placeholder: "customer@example.org"
|
||||
inventory:
|
||||
title: Inventory
|
||||
description: Use this page to manage inventories for your enterprises. Any product details set here will override those set on the 'Products' page
|
||||
@@ -105,6 +115,32 @@ en:
|
||||
enterprise:
|
||||
select_outgoing_oc_products_from: Select outgoing OC products from
|
||||
|
||||
enterprises:
|
||||
form:
|
||||
primary_details:
|
||||
shopfront_requires_login: "Shopfront requires login?"
|
||||
shopfront_requires_login_tip: "Choose whether customers must login to view the shopfront."
|
||||
shopfront_requires_login_false: "Public"
|
||||
shopfront_requires_login_true: "Require customers to login"
|
||||
|
||||
home:
|
||||
hubs:
|
||||
show_closed_shops: "Show closed shops"
|
||||
hide_closed_shops: "Hide closed shops"
|
||||
show_on_map: "Show all on the map"
|
||||
shared:
|
||||
register_call:
|
||||
selling_on_ofn: "Interested in getting on the Open Food Network?"
|
||||
register: "Register here"
|
||||
shop:
|
||||
messages:
|
||||
login: "login"
|
||||
register: "register"
|
||||
contact: "contact"
|
||||
require_customer_login: "This shop is for customers only."
|
||||
require_login_html: "Please %{login} if you have an account already. Otherwise, %{register} to become a customer."
|
||||
require_customer_html: "Please %{contact} %{enterprise} to become a customer."
|
||||
|
||||
# Printable Invoice Columns
|
||||
invoice_column_item: "Item"
|
||||
invoice_column_qty: "Qty"
|
||||
@@ -145,8 +181,6 @@ en:
|
||||
on_demand: On demand
|
||||
none: None
|
||||
|
||||
alert_selling_on_ofn: "Interested in selling food on the Open Food Network?"
|
||||
alert_start_here: "Start here"
|
||||
label_shops: "Shops"
|
||||
label_map: "Map"
|
||||
label_producers: "Producers"
|
||||
@@ -748,7 +782,7 @@ Please follow the instructions there to make your enterprise visible on the Open
|
||||
shop_variant_quantity_max: "max"
|
||||
contact: "Contact"
|
||||
follow: "Follow"
|
||||
shop_for_products_html: "Shop for <span class=\"turquoise\">%{enterprise}</span> products at:" #FIXME
|
||||
shop_for_products_html: "Shop for <span class=\"turquoise\">%{enterprise}</span> products at:"
|
||||
change_shop: "Change shop to:"
|
||||
shop_at: "Shop now at:"
|
||||
price_breakdown: "Full price breakdown"
|
||||
@@ -840,13 +874,12 @@ Please follow the instructions there to make your enterprise visible on the Open
|
||||
go: "Go"
|
||||
hub: "Hub"
|
||||
accounts_administration_distributor: "accounts administration distributor"
|
||||
admin_accounts_and_billing: "admin.accounts_and_billing_settings" #FIXME
|
||||
accounts_and_billing: "Accounts & Billing"
|
||||
producer: "Producer"
|
||||
product: "Product"
|
||||
price: "Price"
|
||||
on_hand: "On hand"
|
||||
save_changes: "Save Changes"
|
||||
update_action: "update()" #FIXME
|
||||
spree_admin_overview_enterprises_header: "My Enterprises"
|
||||
spree_admin_overview_enterprises_footer: "MANAGE MY ENTERPRISES"
|
||||
spree_admin_enterprises_hubs_name: "Name"
|
||||
@@ -882,8 +915,8 @@ Please follow the instructions there to make your enterprise visible on the Open
|
||||
live: "live"
|
||||
manage: "Manage"
|
||||
resend: "Resend"
|
||||
add_and_manage_products: "Add & manage products"
|
||||
add_and_manage_order_cycles: "Add & manage order cycles"
|
||||
add_and_manage_products: "Add & manage products"
|
||||
add_and_manage_order_cycles: "Add & manage order cycles"
|
||||
manage_order_cycles: "Manage order cycles"
|
||||
manage_products: "Manage products"
|
||||
edit_profile_details: "Edit profile details"
|
||||
@@ -916,14 +949,13 @@ Please follow the instructions there to make your enterprise visible on the Open
|
||||
hub_sidebar_at_least: "At least one hub must be selected"
|
||||
hub_sidebar_blue: "blue"
|
||||
hub_sidebar_red: "red"
|
||||
shop_trial_in_progress: "Your shopfront trial expires in #{remaining_trial_days(enterprise)}." #FIXME
|
||||
shop_trial_in_progress: "Your shopfront trial expires in %{days}."
|
||||
shop_trial_expired: "Good news! We have decided to extend shopfront trials until further notice (probably around March 2015)." #FIXME
|
||||
report_customers_distributor: "Distributor"
|
||||
report_customers_supplier: "Supplier"
|
||||
report_customers_cycle: "Order Cycle"
|
||||
report_customers_type: "Report Type"
|
||||
report_customers_csv: "Download as csv"
|
||||
report_customers_header: "orders header"
|
||||
report_producers: "Producers: "
|
||||
report_type: "Report Type: "
|
||||
report_hubs: "Hubs: "
|
||||
@@ -934,8 +966,6 @@ Please follow the instructions there to make your enterprise visible on the Open
|
||||
report_payment_totals: 'Payment Totals'
|
||||
report_all: 'all'
|
||||
report_order_cycle: "Order Cycle: "
|
||||
report_product_header: "products_header"
|
||||
report_order_header: "orders_header"
|
||||
report_entreprises: "Enterprises: "
|
||||
report_users: "Users: "
|
||||
initial_invoice_number: "Initial invoice number:"
|
||||
@@ -944,6 +974,7 @@ Please follow the instructions there to make your enterprise visible on the Open
|
||||
account_code: "Account code:"
|
||||
equals: "Equals"
|
||||
contains: "contains"
|
||||
discount: "Discount"
|
||||
filter_products: "Filter Products"
|
||||
delete_product_variant: "The last variant cannot be deleted!"
|
||||
progress: "progress"
|
||||
@@ -972,6 +1003,7 @@ Please follow the instructions there to make your enterprise visible on the Open
|
||||
payment_methods: "Payment Methods"
|
||||
enterprise_fees: "Enterprise Fees"
|
||||
inventory_settings: "Inventory Settings"
|
||||
tag_rules: "Tag Rules"
|
||||
shop_preferences: "Shop Preferences"
|
||||
validation_msg_relationship_already_established: "^That relationship is already established."
|
||||
validation_msg_at_least_one_hub: "^At least one hub must be selected"
|
||||
|
||||
@@ -87,6 +87,8 @@ Openfoodnetwork::Application.routes.draw do
|
||||
resources :producer_properties do
|
||||
post :update_positions, on: :collection
|
||||
end
|
||||
|
||||
resources :tag_rules, only: [:destroy]
|
||||
end
|
||||
|
||||
resources :enterprise_relationships
|
||||
@@ -113,7 +115,7 @@ Openfoodnetwork::Application.routes.draw do
|
||||
|
||||
resources :inventory_items, only: [:create, :update]
|
||||
|
||||
resources :customers, only: [:index, :update]
|
||||
resources :customers, only: [:index, :create, :update, :destroy]
|
||||
|
||||
resource :content
|
||||
|
||||
@@ -141,6 +143,10 @@ Openfoodnetwork::Application.routes.draw do
|
||||
get :managed, on: :collection
|
||||
get :accessible, on: :collection
|
||||
end
|
||||
|
||||
resource :status do
|
||||
get :job_queue
|
||||
end
|
||||
end
|
||||
|
||||
namespace :open_food_network do
|
||||
|
||||
@@ -4,8 +4,11 @@ require 'whenever'
|
||||
|
||||
env "MAILTO", "rohan@rohanmitchell.com"
|
||||
|
||||
|
||||
# If we use -e with a file containing specs, rspec interprets it and filters out our examples
|
||||
job_type :run_file, "cd :path; :environment_variable=:environment bundle exec script/rails runner :task :output"
|
||||
job_type :enqueue_job, "cd :path; :environment_variable=:environment bundle exec script/enqueue :task :priority :output"
|
||||
|
||||
|
||||
every 1.hour do
|
||||
rake 'openfoodnetwork:cache:check_products_integrity'
|
||||
@@ -23,6 +26,10 @@ every 4.hours do
|
||||
rake 'db2fog:backup'
|
||||
end
|
||||
|
||||
every 5.minutes do
|
||||
enqueue_job 'HeartbeatJob', priority: 0
|
||||
end
|
||||
|
||||
every 1.day, at: '1:00am' do
|
||||
rake 'openfoodnetwork:billing:update_account_invoices'
|
||||
end
|
||||
|
||||
10
db/migrate/20160303004210_create_tag_rules.rb
Normal file
10
db/migrate/20160303004210_create_tag_rules.rb
Normal file
@@ -0,0 +1,10 @@
|
||||
class CreateTagRules < ActiveRecord::Migration
|
||||
def change
|
||||
create_table :tag_rules do |t|
|
||||
t.references :enterprise, null: false, index: true
|
||||
t.string :type, null: false
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
class AddRequireLoginToEnterprise < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :enterprises, :require_login, :boolean, default: false, null: false
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,15 @@
|
||||
class ChangeValueTypeOfPaypalPasswords < ActiveRecord::Migration
|
||||
def up
|
||||
Spree::Preference
|
||||
.where("key like ?", "spree/gateway/pay_pal_express/password/%")
|
||||
.where(value_type: "string")
|
||||
.update_all(value_type: "password")
|
||||
end
|
||||
|
||||
def down
|
||||
Spree::Preference
|
||||
.where("key like ?", "spree/gateway/pay_pal_express/password/%")
|
||||
.where(value_type: "password")
|
||||
.update_all(value_type: "string")
|
||||
end
|
||||
end
|
||||
10
db/schema.rb
10
db/schema.rb
@@ -11,7 +11,7 @@
|
||||
#
|
||||
# It's strongly recommended to check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(:version => 20160302044850) do
|
||||
ActiveRecord::Schema.define(:version => 20160401043927) do
|
||||
|
||||
create_table "account_invoices", :force => true do |t|
|
||||
t.integer "user_id", :null => false
|
||||
@@ -348,6 +348,7 @@ ActiveRecord::Schema.define(:version => 20160302044850) do
|
||||
t.string "permalink", :null => false
|
||||
t.boolean "charges_sales_tax", :default => false, :null => false
|
||||
t.string "email_address"
|
||||
t.boolean "require_login", :default => false, :null => false
|
||||
end
|
||||
|
||||
add_index "enterprises", ["address_id"], :name => "index_enterprises_on_address_id"
|
||||
@@ -1146,6 +1147,13 @@ ActiveRecord::Schema.define(:version => 20160302044850) do
|
||||
t.integer "state_id"
|
||||
end
|
||||
|
||||
create_table "tag_rules", :force => true do |t|
|
||||
t.integer "enterprise_id", :null => false
|
||||
t.string "type", :null => false
|
||||
t.datetime "created_at", :null => false
|
||||
t.datetime "updated_at", :null => false
|
||||
end
|
||||
|
||||
create_table "taggings", :force => true do |t|
|
||||
t.integer "tag_id"
|
||||
t.integer "taggable_id"
|
||||
|
||||
@@ -31,7 +31,7 @@ module OpenFoodNetwork
|
||||
ba.phone,
|
||||
order.distributor.andand.name,
|
||||
[da.andand.address1, da.andand.address2, da.andand.city].join(" "),
|
||||
order.shipping_method.andand.name
|
||||
order.shipping_method.andand.name
|
||||
]
|
||||
end
|
||||
end
|
||||
@@ -78,4 +78,3 @@ module OpenFoodNetwork
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user