mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-12 18:36:49 +00:00
Compare commits
569 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95819c9a0f | ||
|
|
20cabe6f12 | ||
|
|
fe849b8dfd | ||
|
|
167b44c30f | ||
|
|
ad247e2116 | ||
|
|
e46875376e | ||
|
|
d7223c508a | ||
|
|
a91a23aa39 | ||
|
|
370f66e36b | ||
|
|
f7cdcf02e0 | ||
|
|
1ee43fb495 | ||
|
|
e139d24639 | ||
|
|
0dfe749496 | ||
|
|
d6eade6fa3 | ||
|
|
109aed684e | ||
|
|
35d76ac991 | ||
|
|
1ab9e9d7a5 | ||
|
|
e5e716e150 | ||
|
|
b6510c3ab6 | ||
|
|
a158a986c6 | ||
|
|
c7643db66f | ||
|
|
eb8c22aa06 | ||
|
|
d0656485d7 | ||
|
|
640cc1b6d3 | ||
|
|
d65d17a9f3 | ||
|
|
bbea00e431 | ||
|
|
3cecba70e8 | ||
|
|
8bbff09066 | ||
|
|
a7a89d7ccb | ||
|
|
3ccf76ff5f | ||
|
|
6004208496 | ||
|
|
3ce9c712cf | ||
|
|
bfb0032fd2 | ||
|
|
fe37516ead | ||
|
|
289b75e143 | ||
|
|
09f0f8c33f | ||
|
|
8bc1718978 | ||
|
|
cbfce69a6d | ||
|
|
4e0ecdd44c | ||
|
|
23ab9a4bed | ||
|
|
f623446e3e | ||
|
|
6944fe1e46 | ||
|
|
7c9e3d7f06 | ||
|
|
bdcadf9fc6 | ||
|
|
9b7139fd45 | ||
|
|
543e275d2e | ||
|
|
560fa6b949 | ||
|
|
dbf34da87b | ||
|
|
d6022062e1 | ||
|
|
b082d3301b | ||
|
|
48cd542138 | ||
|
|
e2d341c9c2 | ||
|
|
89873a2640 | ||
|
|
b4be2cc2d4 | ||
|
|
35f89a9750 | ||
|
|
592a53b6f5 | ||
|
|
eab9d42eb0 | ||
|
|
cf05369ca9 | ||
|
|
5077b0e625 | ||
|
|
1299c0b5eb | ||
|
|
a2bc61cb4d | ||
|
|
057572a445 | ||
|
|
3403ab4162 | ||
|
|
9a036d18b7 | ||
|
|
f2b57057cd | ||
|
|
95bc8fa984 | ||
|
|
54c44c33eb | ||
|
|
8a732568e7 | ||
|
|
f4523f0305 | ||
|
|
56a7a49ea2 | ||
|
|
7d1ae3bf67 | ||
|
|
b9aa4e11da | ||
|
|
96428c11c6 | ||
|
|
c15660da0e | ||
|
|
9ea05b0794 | ||
|
|
c5b939c8ee | ||
|
|
c5a17bcde0 | ||
|
|
b712ec7f13 | ||
|
|
32a7f13dd2 | ||
|
|
713769b497 | ||
|
|
495de37620 | ||
|
|
05d24cf11a | ||
|
|
edd84530af | ||
|
|
6677543de0 | ||
|
|
30aa31252b | ||
|
|
b83d74a609 | ||
|
|
d31b50be3d | ||
|
|
42e3f2f2f4 | ||
|
|
96737da128 | ||
|
|
7f9f0d840c | ||
|
|
686840e262 | ||
|
|
2377b833ee | ||
|
|
3f3c33bce6 | ||
|
|
e35eff95bb | ||
|
|
e6408161db | ||
|
|
4540b32d3a | ||
|
|
9f8d2fddbc | ||
|
|
14047c620a | ||
|
|
2be1c231f7 | ||
|
|
c34646724c | ||
|
|
b731635270 | ||
|
|
c9a62fad4c | ||
|
|
70169d477c | ||
|
|
d95646ea98 | ||
|
|
d50bf928e1 | ||
|
|
3f7aff4b8b | ||
|
|
de9476a8a5 | ||
|
|
5fded022d4 | ||
|
|
bce41a2247 | ||
|
|
1f644f4020 | ||
|
|
cc11d4e5f0 | ||
|
|
5ecac77aa5 | ||
|
|
a5d2579c69 | ||
|
|
112adb11db | ||
|
|
5fdc11bdc7 | ||
|
|
c038b485b1 | ||
|
|
19eb93012c | ||
|
|
d998ec8453 | ||
|
|
0c93665030 | ||
|
|
c4d298d732 | ||
|
|
36883bc051 | ||
|
|
8c252fc160 | ||
|
|
c2f8803d72 | ||
|
|
07967275d8 | ||
|
|
c7db1b7fc0 | ||
|
|
fa57d71a23 | ||
|
|
be5e7bd18d | ||
|
|
5cfc2613ac | ||
|
|
903eb23122 | ||
|
|
d162e8c087 | ||
|
|
75a56c2be5 | ||
|
|
07a5963554 | ||
|
|
a6888cf0be | ||
|
|
ef35db6db2 | ||
|
|
375d4fbffd | ||
|
|
6153789055 | ||
|
|
032741c54f | ||
|
|
e9acf6e0de | ||
|
|
d5e90c3c6c | ||
|
|
7e7429446d | ||
|
|
535e389fb4 | ||
|
|
cecebb82f4 | ||
|
|
49665ae360 | ||
|
|
7e5c194515 | ||
|
|
fe0b3172c7 | ||
|
|
5b27ed6b9f | ||
|
|
bef4741e31 | ||
|
|
d604328bfb | ||
|
|
2af3de51c7 | ||
|
|
d0c77a8dc4 | ||
|
|
8fc4ca6f65 | ||
|
|
721a0d3a98 | ||
|
|
c46fe7b675 | ||
|
|
bb372984e1 | ||
|
|
2489a2f5f5 | ||
|
|
a6698230fe | ||
|
|
50731e929e | ||
|
|
baa09b88f7 | ||
|
|
2f3509bf9b | ||
|
|
e8f9ace8e6 | ||
|
|
04270b6cec | ||
|
|
1155931ea9 | ||
|
|
efd450606e | ||
|
|
2f60a85593 | ||
|
|
78cf35807a | ||
|
|
f3bc038c05 | ||
|
|
7817a40a35 | ||
|
|
a18f6f5b8f | ||
|
|
403653381c | ||
|
|
eb85dccac1 | ||
|
|
f32454b404 | ||
|
|
591efecde6 | ||
|
|
24afa21885 | ||
|
|
cd6d34663e | ||
|
|
c66e5fe1e9 | ||
|
|
4ec8fcd3a6 | ||
|
|
88893a2968 | ||
|
|
62599e8dfc | ||
|
|
b97c428f72 | ||
|
|
42b074f02e | ||
|
|
07e0951490 | ||
|
|
fc433ff8f0 | ||
|
|
8e33437fbb | ||
|
|
a5103c737d | ||
|
|
37c8f42244 | ||
|
|
0e8765636b | ||
|
|
6855e5c8f4 | ||
|
|
a96b56239c | ||
|
|
4f9eee2682 | ||
|
|
44761315c2 | ||
|
|
0d18b1a032 | ||
|
|
cc0dabcd1e | ||
|
|
e79c672263 | ||
|
|
bc6f7934e0 | ||
|
|
89029f46f9 | ||
|
|
144369e55f | ||
|
|
3833cbbf73 | ||
|
|
5b703a02cd | ||
|
|
1d4aebd3f9 | ||
|
|
845a764320 | ||
|
|
c66579a22f | ||
|
|
9291bf5c82 | ||
|
|
4781ab93ef | ||
|
|
def9ab7c47 | ||
|
|
2a68d34fb0 | ||
|
|
2ce56aef2c | ||
|
|
20f965731d | ||
|
|
8378dce752 | ||
|
|
d7a4e3a896 | ||
|
|
7d9de0ca70 | ||
|
|
f9c6f09cd4 | ||
|
|
4a83eca832 | ||
|
|
4954db64b3 | ||
|
|
b2c4b97d94 | ||
|
|
32c1eecece | ||
|
|
6d8c7a4bee | ||
|
|
bd2045cad7 | ||
|
|
e1c3d2442a | ||
|
|
3df65d0463 | ||
|
|
822a17f732 | ||
|
|
ffde0307e2 | ||
|
|
9e57807dc2 | ||
|
|
052bac196b | ||
|
|
00e789b95b | ||
|
|
a004822019 | ||
|
|
49f7b4c8e2 | ||
|
|
8b503b51ca | ||
|
|
4e431ecf18 | ||
|
|
81f8b127db | ||
|
|
f9f81086fd | ||
|
|
9807b432f9 | ||
|
|
6b0f3cd4f3 | ||
|
|
3c412b7b7d | ||
|
|
c4e6c0af2b | ||
|
|
e6387197ec | ||
|
|
746c4f03f6 | ||
|
|
3535c4d564 | ||
|
|
37abdb7727 | ||
|
|
bdb3dd5aaf | ||
|
|
25fbab2e37 | ||
|
|
4d37aaac64 | ||
|
|
19e28cb14a | ||
|
|
a44a251d96 | ||
|
|
2921ee19e1 | ||
|
|
6796d91a07 | ||
|
|
69afcf7510 | ||
|
|
47056e3cc1 | ||
|
|
311ee92e84 | ||
|
|
241e97d938 | ||
|
|
85b1ba8eae | ||
|
|
baa4783141 | ||
|
|
ce40fcaf7b | ||
|
|
40438de7fe | ||
|
|
29dcd96fca | ||
|
|
7fd6a7e654 | ||
|
|
8f2a80f199 | ||
|
|
ea41405209 | ||
|
|
2683efdd3c | ||
|
|
ed1c154b78 | ||
|
|
4aba2730f7 | ||
|
|
07ae51560e | ||
|
|
3c5c842bbf | ||
|
|
e7e4508555 | ||
|
|
9a3b5d0700 | ||
|
|
46353be9a3 | ||
|
|
91a52ead58 | ||
|
|
0f55049eda | ||
|
|
83f1a7a9a9 | ||
|
|
fac118fce2 | ||
|
|
5270cdaa32 | ||
|
|
caebcdf184 | ||
|
|
c66a659e8e | ||
|
|
b8b107dd2d | ||
|
|
ecf336fe51 | ||
|
|
a3efd13d46 | ||
|
|
2ff0169016 | ||
|
|
08d37bbed7 | ||
|
|
b71443ccd8 | ||
|
|
8fd3d9e03c | ||
|
|
787727872f | ||
|
|
5bf72ae780 | ||
|
|
290d00f17d | ||
|
|
3d7bbbbb19 | ||
|
|
3d32987227 | ||
|
|
902e51e580 | ||
|
|
743cb3b33a | ||
|
|
74e49787f4 | ||
|
|
afa8f97627 | ||
|
|
6e677fecce | ||
|
|
889a3e6d9d | ||
|
|
664be47ac3 | ||
|
|
fd77f48aca | ||
|
|
9a31b99de6 | ||
|
|
0e4b5ad9ec | ||
|
|
5634f4af18 | ||
|
|
0dede39617 | ||
|
|
d98e302047 | ||
|
|
377b4a3755 | ||
|
|
0c809b2911 | ||
|
|
33472014f1 | ||
|
|
d038c27f1f | ||
|
|
3d718d9738 | ||
|
|
500ef901fd | ||
|
|
a15db65e69 | ||
|
|
64a501ee20 | ||
|
|
95fcff8bb1 | ||
|
|
a2e6b84db2 | ||
|
|
d319f97733 | ||
|
|
c0bf7e2e75 | ||
|
|
1d177a164b | ||
|
|
d846c31db9 | ||
|
|
efd01f8c9e | ||
|
|
fb65c64c68 | ||
|
|
b8d8ee4edc | ||
|
|
936784404e | ||
|
|
11ea852211 | ||
|
|
4656c35f71 | ||
|
|
254315b79e | ||
|
|
cc7461e692 | ||
|
|
c4d5eec7fd | ||
|
|
2dc85463ce | ||
|
|
aa3bd93ad0 | ||
|
|
24c8bb95cb | ||
|
|
2e361baeaa | ||
|
|
a98a0bd264 | ||
|
|
b4de8ef899 | ||
|
|
f0586af1c7 | ||
|
|
e9b5551c0f | ||
|
|
7cec24f1d4 | ||
|
|
26f5ece7c0 | ||
|
|
a21a4aba5d | ||
|
|
f413ce2a27 | ||
|
|
5847b1a51e | ||
|
|
f51ebc63c3 | ||
|
|
908e1dfcaf | ||
|
|
5bc2c96248 | ||
|
|
ab8c7bad76 | ||
|
|
55883a0efc | ||
|
|
2e519957ec | ||
|
|
cd5b3c7393 | ||
|
|
eb9f02f3bd | ||
|
|
a1f3e8205f | ||
|
|
410e23085e | ||
|
|
e2b3ee7b3f | ||
|
|
242767dc73 | ||
|
|
8e8c77c5bd | ||
|
|
e3ce2a7486 | ||
|
|
8524f49589 | ||
|
|
36f9cd9cbf | ||
|
|
0fab4a3a8e | ||
|
|
722884d8d8 | ||
|
|
23740ef908 | ||
|
|
ba04208999 | ||
|
|
590ce67f38 | ||
|
|
e11ea929c3 | ||
|
|
f88d54b862 | ||
|
|
fc9f61ecf8 | ||
|
|
6d283ac839 | ||
|
|
725807f66d | ||
|
|
149df6569c | ||
|
|
7daa7032aa | ||
|
|
8b7119beea | ||
|
|
201e87bf12 | ||
|
|
0fffd6b4e3 | ||
|
|
c516d40d4a | ||
|
|
07d4528276 | ||
|
|
4ace780431 | ||
|
|
b69c3fd826 | ||
|
|
51df8de64f | ||
|
|
d4a5829858 | ||
|
|
ff5fe66994 | ||
|
|
37e50a68e4 | ||
|
|
a72c662b97 | ||
|
|
ff2db0c5f8 | ||
|
|
e9c60a33b9 | ||
|
|
8e059d3c69 | ||
|
|
806ba94a2e | ||
|
|
4bec583bff | ||
|
|
90256f9c28 | ||
|
|
eb284c1742 | ||
|
|
b614e17f48 | ||
|
|
1a450733a3 | ||
|
|
ffde7a38df | ||
|
|
8b4b0621db | ||
|
|
5259eaae5f | ||
|
|
b0ad0fccfa | ||
|
|
2a83ad8689 | ||
|
|
c127110192 | ||
|
|
0470725112 | ||
|
|
0623bab084 | ||
|
|
4a0df684c7 | ||
|
|
7dccb5ba90 | ||
|
|
5a4be24df0 | ||
|
|
5cb5967977 | ||
|
|
aeb8d30dae | ||
|
|
1822fd97a6 | ||
|
|
4ff3e9fe10 | ||
|
|
a63994440d | ||
|
|
f6d0de1454 | ||
|
|
9b0e27a9d1 | ||
|
|
415d88f302 | ||
|
|
f9c98ea9a1 | ||
|
|
369a5a8a2f | ||
|
|
62341c6381 | ||
|
|
fa1becb791 | ||
|
|
50a1704994 | ||
|
|
302538c370 | ||
|
|
0f80b6ce12 | ||
|
|
69fb8b2afe | ||
|
|
1df8fc903e | ||
|
|
9a2dcb89af | ||
|
|
1661591f6c | ||
|
|
6dde720039 | ||
|
|
a54b725d6d | ||
|
|
265e76e8ca | ||
|
|
192bff4fed | ||
|
|
92a270165e | ||
|
|
9f5c9916ba | ||
|
|
d08de4bdf9 | ||
|
|
45bdb85bf3 | ||
|
|
ece0652ca3 | ||
|
|
7a652fd67b | ||
|
|
4ca8feeef1 | ||
|
|
367932a767 | ||
|
|
e591658f48 | ||
|
|
1516069888 | ||
|
|
cd263b761c | ||
|
|
c952ad16ad | ||
|
|
ca09c58f26 | ||
|
|
e876a25d59 | ||
|
|
2a780151be | ||
|
|
9d2009d2af | ||
|
|
f887533dda | ||
|
|
bef3f154d6 | ||
|
|
6fb775d5ed | ||
|
|
b5a8563725 | ||
|
|
1a9ade6de9 | ||
|
|
48df853ff5 | ||
|
|
2137a2addb | ||
|
|
e6a7239716 | ||
|
|
25bed92f2e | ||
|
|
909cd407dd | ||
|
|
f2d25748b1 | ||
|
|
6396e6e970 | ||
|
|
e52f813dae | ||
|
|
9ab2eec30c | ||
|
|
f96b37dae3 | ||
|
|
5b68b2f707 | ||
|
|
ff634bd870 | ||
|
|
7d21d88dc9 | ||
|
|
31b62d6296 | ||
|
|
5e68604f11 | ||
|
|
c4edd3a683 | ||
|
|
574781e901 | ||
|
|
8ea4f933da | ||
|
|
1e9820f291 | ||
|
|
34ed86cf2d | ||
|
|
8a4e5b445f | ||
|
|
2394eda2ac | ||
|
|
f97a3a030a | ||
|
|
ec645f8fa8 | ||
|
|
56a54db602 | ||
|
|
4c3d15b42b | ||
|
|
5f4429646d | ||
|
|
f37db456f8 | ||
|
|
2dfcedad56 | ||
|
|
706168f2f0 | ||
|
|
3ecb5c0c75 | ||
|
|
249a3c4e18 | ||
|
|
2b8ebba233 | ||
|
|
758394464b | ||
|
|
d3c624ae10 | ||
|
|
163c65849e | ||
|
|
99ff714913 | ||
|
|
c2f302450f | ||
|
|
9186bcd455 | ||
|
|
3d074b530f | ||
|
|
20783db373 | ||
|
|
b9ddb39edc | ||
|
|
53496ff9eb | ||
|
|
c1248857b8 | ||
|
|
e2d61f5e89 | ||
|
|
5a1ef04c67 | ||
|
|
e9e73ef0e4 | ||
|
|
001e3688da | ||
|
|
e5a9606449 | ||
|
|
1217811402 | ||
|
|
bf2c1a0c1d | ||
|
|
5d83414e9b | ||
|
|
2f5b0a5afb | ||
|
|
b3728568a8 | ||
|
|
6ba98b4b2c | ||
|
|
006c6e6b7b | ||
|
|
41aa4ff479 | ||
|
|
0e8f167ab9 | ||
|
|
4aa6c673ff | ||
|
|
aa3c1aa0fe | ||
|
|
31bac9641f | ||
|
|
60bdde6349 | ||
|
|
5faf33fabe | ||
|
|
f3b1a5dd35 | ||
|
|
07ccbf7f98 | ||
|
|
b7f7038934 | ||
|
|
6c054e6078 | ||
|
|
18974c68e1 | ||
|
|
78ab852141 | ||
|
|
4497173213 | ||
|
|
4d74d246e8 | ||
|
|
cc51537e93 | ||
|
|
07aececdcf | ||
|
|
c3fbf9cdf9 | ||
|
|
180598c603 | ||
|
|
69a5527e24 | ||
|
|
e4a6b3880f | ||
|
|
96ce4deb45 | ||
|
|
a3c179bd3f | ||
|
|
a57504ba1f | ||
|
|
25451eed6b | ||
|
|
50765563f8 | ||
|
|
2ae75ce13e | ||
|
|
18aa16650d | ||
|
|
314ed50e0f | ||
|
|
7346a49982 | ||
|
|
5182286218 | ||
|
|
a267848394 | ||
|
|
104bd31f9b | ||
|
|
8bc9985edb | ||
|
|
6dfc927730 | ||
|
|
3771e26eba | ||
|
|
fd21d35aee | ||
|
|
1417b924d2 | ||
|
|
2912c1b87d | ||
|
|
e746a0db7d | ||
|
|
84a2886003 | ||
|
|
c668677b8a | ||
|
|
2490cbfccb | ||
|
|
20a46a791c | ||
|
|
0e4fe08ac4 | ||
|
|
cf0f716534 | ||
|
|
b70cfa5968 | ||
|
|
f77beb50ff | ||
|
|
a941280982 | ||
|
|
9d40ee49e6 | ||
|
|
6abbdecb97 | ||
|
|
660ce92c27 | ||
|
|
c5bcef6ae4 | ||
|
|
d26a0b6b73 | ||
|
|
ec6f6056a8 | ||
|
|
c464b21d76 | ||
|
|
c83d249147 | ||
|
|
a11562e4dd | ||
|
|
2d872c25bf | ||
|
|
986837d601 | ||
|
|
353d6fbc5f | ||
|
|
0a88738faa | ||
|
|
4d6af57f79 | ||
|
|
110fd3ecdf | ||
|
|
1cb065f829 | ||
|
|
1cfa499b0e | ||
|
|
3fc0d4a666 | ||
|
|
de6c96d138 | ||
|
|
11974689ef | ||
|
|
e1fce8304d | ||
|
|
0d6ba90ea1 | ||
|
|
4398ea12b8 | ||
|
|
160b535e2f | ||
|
|
e8eeb3d5dc | ||
|
|
4551149532 | ||
|
|
82955b9fe5 |
66
.github/ISSUE_TEMPLATE.md
vendored
66
.github/ISSUE_TEMPLATE.md
vendored
@@ -1,66 +0,0 @@
|
||||
<!-- Provide a general summary of the issue in the Title above.
|
||||
|
||||
If your issue is not a bug, please use the Feature template instead:
|
||||
https://github.com/openfoodfoundation/openfoodnetwork/wiki/Feature-template
|
||||
|
||||
-->
|
||||
## Description
|
||||
<!-- Provide a more detailed introduction to the issue itself, and why you consider it to be a bug -->
|
||||
|
||||
|
||||
|
||||
## Expected Behavior
|
||||
<!-- Tell us what should happen -->
|
||||
|
||||
|
||||
|
||||
## Actual Behavior
|
||||
<!-- Tell us what happens instead -->
|
||||
|
||||
|
||||
|
||||
## Steps to Reproduce
|
||||
<!-- Provide an unambiguous set of steps to reproduce this bug -->
|
||||
<!-- Include code to reproduce if relevant -->
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
4.
|
||||
|
||||
## Animated Gif/Screenshot
|
||||
<!-- Provide a screenshot or brief animated gif reproducing the bug. Linux users can use
|
||||
[Peek](https://github.com/phw/peek#ubuntu) while Mac users can use [Recordit](http://recordit.co/) -->
|
||||
|
||||
|
||||
|
||||
## Context
|
||||
<!-- How has this bug affected you? What were you trying to accomplish? -->
|
||||
|
||||
|
||||
|
||||
## Severity
|
||||
<!-- Assign a label and explain the impact.
|
||||
|
||||
bug-s1: a critical feature is broken: checkout, payments, signup, login
|
||||
bug-s2: a non-critical feature is broken, no workaround
|
||||
bug-s3: a feature is broken but there is a workaround
|
||||
bug-s4: it's annoying, but you can use it
|
||||
bug-s5: we can live with it, only a few users impacted
|
||||
|
||||
https://github.com/openfoodfoundation/openfoodnetwork/wiki/Bug-severity
|
||||
-->
|
||||
|
||||
|
||||
|
||||
## Your Environment
|
||||
<!-- Include relevant details about the environment you experienced the bug in -->
|
||||
|
||||
* Version used:
|
||||
* Browser name and version:
|
||||
* Operating System and version (desktop or mobile):
|
||||
|
||||
## Possible Fix
|
||||
<!-- Not obligatory, but suggest a fix or reason for the bug -->
|
||||
|
||||
|
||||
14
.github/ISSUE_TEMPLATE/bug_report.md
vendored
14
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -9,6 +9,7 @@ assignees: ''
|
||||
|
||||
## Description
|
||||
<!-- Provide a more detailed introduction to the issue itself, and why you consider it to be a bug -->
|
||||
<!-- How has this bug affected you? What were you trying to accomplish? -->
|
||||
|
||||
|
||||
## Expected Behavior
|
||||
@@ -22,6 +23,8 @@ assignees: ''
|
||||
## Steps to Reproduce
|
||||
<!-- Provide an unambiguous set of steps to reproduce this bug -->
|
||||
<!-- Include code to reproduce if relevant -->
|
||||
<!-- Include links -->
|
||||
<!-- Include user ID -->
|
||||
|
||||
1.
|
||||
2.
|
||||
@@ -29,13 +32,11 @@ assignees: ''
|
||||
4.
|
||||
|
||||
## Animated Gif/Screenshot
|
||||
<!-- Provide a screenshot or brief animated gif reproducing the bug. Linux users can use
|
||||
[Peek](https://github.com/phw/peek#ubuntu) while Mac users can use [Recordit](http://recordit.co/) -->
|
||||
|
||||
|
||||
## Context
|
||||
<!-- How has this bug affected you? What were you trying to accomplish? -->
|
||||
<!-- Provide a screenshot or brief video reproducing the bug. -->
|
||||
<!-- Please try to have the dev tools opened on the network tab (press F12 to open the devtools of your browser -->
|
||||
|
||||
## Workaround
|
||||
<!-- Include a workaround for this bug (if relevant) -->
|
||||
|
||||
## Severity
|
||||
<!-- Assign a label and explain the impact.
|
||||
@@ -55,7 +56,6 @@ https://github.com/openfoodfoundation/openfoodnetwork/wiki/Bug-severity
|
||||
* Version used:
|
||||
* Browser name and version:
|
||||
* Operating System and version (desktop or mobile):
|
||||
* OFN Platform instance where you discovered the bug, and which version of the software they are using.
|
||||
|
||||
## Possible Fix
|
||||
<!-- Not obligatory, but suggest a fix or reason for the bug -->
|
||||
|
||||
11
.github/ISSUE_TEMPLATE/story-template.md
vendored
11
.github/ISSUE_TEMPLATE/story-template.md
vendored
@@ -14,5 +14,12 @@ assignees: ''
|
||||
**- I want to be able to do:** (specify the desired behavior)
|
||||
(Link to others issues or resources to provide context > only if really necessary). -->
|
||||
|
||||
## Acceptance Criteria
|
||||
<!-- Document the outcomes that need to be achieved before this component can be considered complete. -->
|
||||
## Acceptance Criteria & Tests
|
||||
<!-- Document the outcomes that need to be achieved before this component can be considered complete.
|
||||
-->
|
||||
<!-- Provide an unambiguous set of steps a tester should do to validate the PR that will solve this issue -->
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
4.
|
||||
|
||||
@@ -49,7 +49,6 @@ Metrics/LineLength:
|
||||
- app/controllers/spree/admin/orders_controller_decorator.rb
|
||||
- app/controllers/spree/admin/payments_controller_decorator.rb
|
||||
- app/controllers/spree/admin/payment_methods_controller_decorator.rb
|
||||
- app/controllers/spree/admin/products_controller_decorator.rb
|
||||
- app/controllers/spree/admin/reports_controller_decorator.rb
|
||||
- app/controllers/spree/api/products_controller_decorator.rb
|
||||
- app/controllers/spree/credit_cards_controller.rb
|
||||
@@ -111,18 +110,6 @@ Metrics/LineLength:
|
||||
- app/models/variant_override.rb
|
||||
- app/models/variant_override_set.rb
|
||||
- app/overrides/add_enterprise_fees_to_admin_configurations_menu.rb
|
||||
- app/serializers/api/admin/basic_enterprise_serializer.rb
|
||||
- app/serializers/api/admin/enterprise_fee_serializer.rb
|
||||
- app/serializers/api/admin/enterprise_serializer.rb
|
||||
- app/serializers/api/admin/exchange_serializer.rb
|
||||
- app/serializers/api/admin/for_order_cycle/enterprise_serializer.rb
|
||||
- app/serializers/api/admin/index_enterprise_serializer.rb
|
||||
- app/serializers/api/admin/index_order_cycle_serializer.rb
|
||||
- app/serializers/api/admin/line_item_serializer.rb
|
||||
- app/serializers/api/admin/order_cycle_serializer.rb
|
||||
- app/serializers/api/admin/subscription_serializer.rb
|
||||
- app/serializers/api/admin/tag_rule_serializer.rb
|
||||
- app/serializers/api/admin/variant_override_serializer.rb
|
||||
- app/services/cart_service.rb
|
||||
- app/services/default_stock_location.rb
|
||||
- app/services/embedded_page_service.rb
|
||||
@@ -149,7 +136,6 @@ Metrics/LineLength:
|
||||
- lib/open_food_network/order_cycle_form_applicator.rb
|
||||
- lib/open_food_network/order_cycle_management_report.rb
|
||||
- lib/open_food_network/order_grouper.rb
|
||||
- lib/open_food_network/orders_and_fulfillments_report.rb
|
||||
- lib/open_food_network/payments_report.rb
|
||||
- lib/open_food_network/permalink_generator.rb
|
||||
- lib/open_food_network/products_cache.rb
|
||||
@@ -342,7 +328,6 @@ Metrics/LineLength:
|
||||
- spec/performance/orders_controller_spec.rb
|
||||
- spec/performance/shop_controller_spec.rb
|
||||
- spec/requests/checkout/failed_checkout_spec.rb
|
||||
- spec/requests/checkout/stripe_connect_spec.rb
|
||||
- spec/requests/embedded_shopfronts_headers_spec.rb
|
||||
- spec/requests/shop_spec.rb
|
||||
- spec/serializers/admin/customer_serializer_spec.rb
|
||||
@@ -437,7 +422,6 @@ Metrics/AbcSize:
|
||||
- app/models/spree/order_decorator.rb
|
||||
- app/models/spree/payment_decorator.rb
|
||||
- app/models/spree/product_decorator.rb
|
||||
- app/models/spree/product_set.rb
|
||||
- app/models/spree/taxon_decorator.rb
|
||||
- app/serializers/api/admin/enterprise_serializer.rb
|
||||
- app/serializers/api/product_serializer.rb
|
||||
@@ -457,7 +441,6 @@ Metrics/AbcSize:
|
||||
- lib/open_food_network/order_cycle_form_applicator.rb
|
||||
- lib/open_food_network/order_cycle_management_report.rb
|
||||
- lib/open_food_network/order_cycle_permissions.rb
|
||||
- lib/open_food_network/orders_and_fulfillments_report.rb
|
||||
- lib/open_food_network/packing_report.rb
|
||||
- lib/open_food_network/payments_report.rb
|
||||
- lib/open_food_network/permissions.rb
|
||||
@@ -484,63 +467,26 @@ Metrics/AbcSize:
|
||||
|
||||
Metrics/BlockLength:
|
||||
Max: 25
|
||||
ExcludedMethods: ["class_eval", "collection", "context", "describe", "it", "member", "namespace", "resource", "resources"]
|
||||
ExcludedMethods: [
|
||||
"class_eval",
|
||||
"collection",
|
||||
"context",
|
||||
"describe",
|
||||
"feature",
|
||||
"it",
|
||||
"member",
|
||||
"namespace",
|
||||
"resource",
|
||||
"resources",
|
||||
"scenario"
|
||||
]
|
||||
Exclude:
|
||||
- lib/tasks/data.rake
|
||||
- lib/tasks/dev.rake
|
||||
- spec/controllers/spree/admin/invoices_controller_spec.rb
|
||||
- spec/factories/variant_factory.rb
|
||||
- spec/features/admin/adjustments_spec.rb
|
||||
- spec/features/admin/bulk_order_management_spec.rb
|
||||
- spec/features/admin/bulk_product_update_spec.rb
|
||||
- spec/features/admin/caching_spec.rb
|
||||
- spec/features/admin/content_spec.rb
|
||||
- spec/features/admin/customers_spec.rb
|
||||
- spec/features/admin/enterprise_fees_spec.rb
|
||||
- spec/features/admin/enterprise_groups_spec.rb
|
||||
- spec/features/admin/enterprise_relationships_spec.rb
|
||||
- spec/features/admin/enterprise_roles_spec.rb
|
||||
- spec/features/admin/enterprises/images_spec.rb
|
||||
- spec/features/admin/enterprises/index_spec.rb
|
||||
- spec/features/admin/enterprises_spec.rb
|
||||
- spec/features/admin/enterprise_user_spec.rb
|
||||
- spec/features/admin/multilingual_spec.rb
|
||||
- spec/features/admin/order_cycles_spec.rb
|
||||
- spec/features/admin/orders_spec.rb
|
||||
- spec/features/admin/overview_spec.rb
|
||||
- spec/features/admin/payment_method_spec.rb
|
||||
- spec/features/admin/product_import_spec.rb
|
||||
- spec/features/admin/products_spec.rb
|
||||
- spec/features/admin/reports/enterprise_fee_summaries_spec.rb
|
||||
- spec/features/admin/reports_spec.rb
|
||||
- spec/features/admin/schedules_spec.rb
|
||||
- spec/features/admin/shipping_methods_spec.rb
|
||||
- spec/features/admin/subscriptions_spec.rb
|
||||
- spec/features/admin/tag_rules_spec.rb
|
||||
- spec/features/admin/tax_settings_spec.rb
|
||||
- spec/features/admin/users_spec.rb
|
||||
- spec/features/admin/variant_overrides_spec.rb
|
||||
- spec/features/admin/variants_spec.rb
|
||||
- spec/features/consumer/account/cards_spec.rb
|
||||
- spec/features/consumer/account/settings_spec.rb
|
||||
- spec/features/consumer/account_spec.rb
|
||||
- spec/features/consumer/authentication_spec.rb
|
||||
- spec/features/consumer/cookies_spec.rb
|
||||
- spec/features/consumer/external_services_spec.rb
|
||||
- spec/features/consumer/groups_spec.rb
|
||||
- spec/features/consumer/multilingual_spec.rb
|
||||
- spec/features/consumer/producers_spec.rb
|
||||
- spec/features/consumer/registration_spec.rb
|
||||
- spec/features/consumer/shopping/cart_spec.rb
|
||||
- spec/features/consumer/shopping/checkout_auth_spec.rb
|
||||
- spec/features/consumer/shopping/checkout_spec.rb
|
||||
- spec/features/consumer/shopping/embedded_groups_spec.rb
|
||||
- spec/features/consumer/shopping/embedded_shopfronts_spec.rb
|
||||
- spec/features/consumer/shopping/orders_spec.rb
|
||||
- spec/features/consumer/shopping/products_spec.rb
|
||||
- spec/features/consumer/shopping/shopping_spec.rb
|
||||
- spec/features/consumer/shopping/variant_overrides_spec.rb
|
||||
- spec/features/consumer/shops_spec.rb
|
||||
- spec/lib/open_food_network/group_buy_report_spec.rb
|
||||
- spec/models/tag_rule/discount_order_spec.rb
|
||||
- spec/spec_helper.rb
|
||||
@@ -559,6 +505,7 @@ Metrics/CyclomaticComplexity:
|
||||
- app/helpers/checkout_helper.rb
|
||||
- app/helpers/i18n_helper.rb
|
||||
- app/helpers/order_cycles_helper.rb
|
||||
- app/helpers/spree/admin/navigation_helper_decorator.rb
|
||||
- app/models/enterprise.rb
|
||||
- app/models/enterprise_relationship.rb
|
||||
- app/models/product_import/entry_processor.rb
|
||||
@@ -566,13 +513,11 @@ Metrics/CyclomaticComplexity:
|
||||
- app/models/spree/ability_decorator.rb
|
||||
- app/models/spree/payment_decorator.rb
|
||||
- app/models/spree/product_decorator.rb
|
||||
- app/models/spree/product_set.rb
|
||||
- app/models/variant_override_set.rb
|
||||
- app/services/cart_service.rb
|
||||
- lib/discourse/single_sign_on.rb
|
||||
- lib/open_food_network/bulk_coop_report.rb
|
||||
- lib/open_food_network/enterprise_issue_validator.rb
|
||||
- lib/open_food_network/orders_and_fulfillments_report.rb
|
||||
- lib/spree/core/controller_helpers/order_decorator.rb
|
||||
- lib/spree/core/controller_helpers/respond_with_decorator.rb
|
||||
- lib/spree/localized_number.rb
|
||||
@@ -594,11 +539,9 @@ Metrics/PerceivedComplexity:
|
||||
- app/models/spree/ability_decorator.rb
|
||||
- app/models/spree/order_decorator.rb
|
||||
- app/models/spree/product_decorator.rb
|
||||
- app/models/spree/product_set.rb
|
||||
- lib/discourse/single_sign_on.rb
|
||||
- lib/open_food_network/bulk_coop_report.rb
|
||||
- lib/open_food_network/enterprise_issue_validator.rb
|
||||
- lib/open_food_network/orders_and_fulfillments_report.rb
|
||||
- lib/spree/core/controller_helpers/order_decorator.rb
|
||||
- lib/spree/core/controller_helpers/respond_with_decorator.rb
|
||||
- lib/spree/localized_number.rb
|
||||
@@ -650,7 +593,6 @@ Metrics/MethodLength:
|
||||
- app/models/spree/payment_decorator.rb
|
||||
- app/models/spree/payment_method_decorator.rb
|
||||
- app/models/spree/product_decorator.rb
|
||||
- app/models/spree/product_set.rb
|
||||
- app/serializers/api/admin/order_cycle_serializer.rb
|
||||
- app/serializers/api/cached_enterprise_serializer.rb
|
||||
- app/services/order_cycle_form.rb
|
||||
@@ -669,7 +611,6 @@ Metrics/MethodLength:
|
||||
- lib/open_food_network/order_cycle_management_report.rb
|
||||
- lib/open_food_network/order_cycle_permissions.rb
|
||||
- lib/open_food_network/order_grouper.rb
|
||||
- lib/open_food_network/orders_and_fulfillments_report.rb
|
||||
- lib/open_food_network/packing_report.rb
|
||||
- lib/open_food_network/payments_report.rb
|
||||
- lib/open_food_network/permissions.rb
|
||||
@@ -713,7 +654,6 @@ Metrics/ClassLength:
|
||||
- lib/open_food_network/order_cycle_form_applicator.rb
|
||||
- lib/open_food_network/order_cycle_management_report.rb
|
||||
- lib/open_food_network/order_cycle_permissions.rb
|
||||
- lib/open_food_network/orders_and_fulfillments_report.rb
|
||||
- lib/open_food_network/packing_report.rb
|
||||
- lib/open_food_network/payments_report.rb
|
||||
- lib/open_food_network/permissions.rb
|
||||
|
||||
@@ -186,7 +186,19 @@ Metrics/AbcSize:
|
||||
|
||||
Metrics/BlockLength:
|
||||
Max: 25
|
||||
ExcludedMethods: ["class_eval", "collection", "context", "describe", "it", "member", "namespace", "resource", "resources"]
|
||||
ExcludedMethods: [
|
||||
"class_eval",
|
||||
"collection",
|
||||
"context",
|
||||
"describe",
|
||||
"feature",
|
||||
"it",
|
||||
"member",
|
||||
"namespace",
|
||||
"resource",
|
||||
"resources",
|
||||
"scenario"
|
||||
]
|
||||
|
||||
Metrics/BlockNesting:
|
||||
Max: 3
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# This configuration was generated by
|
||||
# `rubocop --auto-gen-config --exclude-limit 1400`
|
||||
# on 2019-05-28 16:29:07 +0100 using RuboCop version 0.57.2.
|
||||
# on 2019-07-23 14:09:18 +0100 using RuboCop version 0.57.2.
|
||||
# The point is for the user to remove these configuration records
|
||||
# one by one as the offenses are removed from the code base.
|
||||
# Note that changes in the inspected code, or installation of new
|
||||
@@ -32,15 +32,6 @@ Layout/EndAlignment:
|
||||
Layout/IndentHash:
|
||||
EnforcedStyle: consistent
|
||||
|
||||
# Offense count: 7
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, IndentationWidth.
|
||||
# SupportedStyles: aligned, indented, indented_relative_to_receiver
|
||||
Layout/MultilineMethodCallIndentation:
|
||||
Exclude:
|
||||
- 'app/models/spree/line_item_decorator.rb'
|
||||
- 'app/models/spree/product_decorator.rb'
|
||||
|
||||
# Offense count: 4
|
||||
Lint/AmbiguousOperator:
|
||||
Exclude:
|
||||
@@ -55,7 +46,7 @@ Lint/DuplicateMethods:
|
||||
- 'lib/discourse/single_sign_on.rb'
|
||||
- 'lib/open_food_network/subscription_summary.rb'
|
||||
|
||||
# Offense count: 15
|
||||
# Offense count: 8
|
||||
Lint/IneffectiveAccessModifier:
|
||||
Exclude:
|
||||
- 'app/models/column_preference.rb'
|
||||
@@ -79,7 +70,13 @@ Lint/UnderscorePrefixedVariableName:
|
||||
Exclude:
|
||||
- 'spec/support/cancan_helper.rb'
|
||||
|
||||
# Offense count: 6
|
||||
# Offense count: 1
|
||||
# Cop supports --auto-correct.
|
||||
Lint/UnneededCopDisableDirective:
|
||||
Exclude:
|
||||
- 'app/models/product_import/entry_validator.rb'
|
||||
|
||||
# Offense count: 5
|
||||
# Configuration parameters: ContextCreatingMethods, MethodCreatingMethods.
|
||||
Lint/UselessAccessModifier:
|
||||
Exclude:
|
||||
@@ -89,28 +86,47 @@ Lint/UselessAccessModifier:
|
||||
- 'lib/open_food_network/reports/bulk_coop_report.rb'
|
||||
- 'spec/lib/open_food_network/reports/report_spec.rb'
|
||||
|
||||
# Offense count: 91
|
||||
# Offense count: 8
|
||||
# Configuration parameters: CheckForMethodsWithNoSideEffects.
|
||||
Lint/Void:
|
||||
Exclude:
|
||||
- 'app/serializers/api/enterprise_serializer.rb'
|
||||
- 'spec/features/admin/bulk_product_update_spec.rb'
|
||||
- 'spec/features/admin/enterprise_groups_spec.rb'
|
||||
- 'spec/features/admin/enterprises/index_spec.rb'
|
||||
- 'spec/features/admin/enterprises_spec.rb'
|
||||
- 'spec/features/admin/order_cycles_spec.rb'
|
||||
- 'spec/features/admin/payment_method_spec.rb'
|
||||
- 'spec/features/admin/products_spec.rb'
|
||||
- 'spec/features/admin/variant_overrides_spec.rb'
|
||||
- 'spec/features/admin/variants_spec.rb'
|
||||
- 'spec/features/consumer/shopping/checkout_spec.rb'
|
||||
- 'spec/features/consumer/shopping/shopping_spec.rb'
|
||||
- 'spec/features/consumer/shopping/variant_overrides_spec.rb'
|
||||
|
||||
# Offense count: 109
|
||||
# Offense count: 15
|
||||
Metrics/AbcSize:
|
||||
Max: 36
|
||||
|
||||
# Offense count: 13
|
||||
# Configuration parameters: CountComments, ExcludedMethods.
|
||||
Metrics/BlockLength:
|
||||
Max: 774
|
||||
Max: 115
|
||||
|
||||
# Offense count: 2
|
||||
# Configuration parameters: CountComments.
|
||||
Metrics/ClassLength:
|
||||
Max: 169
|
||||
|
||||
# Offense count: 1
|
||||
Metrics/CyclomaticComplexity:
|
||||
Max: 8
|
||||
|
||||
# Offense count: 8
|
||||
# Configuration parameters: CountComments.
|
||||
Metrics/MethodLength:
|
||||
Max: 31
|
||||
|
||||
# Offense count: 2
|
||||
# Configuration parameters: CountComments.
|
||||
Metrics/ModuleLength:
|
||||
Max: 208
|
||||
|
||||
# Offense count: 2
|
||||
Metrics/PerceivedComplexity:
|
||||
Max: 11
|
||||
|
||||
# Offense count: 7
|
||||
Naming/AccessorMethodName:
|
||||
@@ -160,7 +176,7 @@ Naming/PredicateName:
|
||||
- 'lib/open_food_network/packing_report.rb'
|
||||
- 'lib/tasks/data.rake'
|
||||
|
||||
# Offense count: 12
|
||||
# Offense count: 11
|
||||
# Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
|
||||
# AllowedNames: io, id, to, by, on, in, at
|
||||
Naming/UncommunicativeMethodParamName:
|
||||
@@ -288,13 +304,12 @@ Style/CaseEquality:
|
||||
- 'app/helpers/angular_form_helper.rb'
|
||||
- 'spec/models/spree/payment_spec.rb'
|
||||
|
||||
# Offense count: 79
|
||||
# Offense count: 78
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: AutoCorrect, EnforcedStyle.
|
||||
# SupportedStyles: nested, compact
|
||||
Style/ClassAndModuleChildren:
|
||||
Exclude:
|
||||
- 'app/controllers/spree/store_controller_decorator.rb'
|
||||
- 'app/helpers/angular_form_helper.rb'
|
||||
- 'app/models/calculator/flat_percent_per_item.rb'
|
||||
- 'app/models/spree/concerns/payment_method_distributors.rb'
|
||||
@@ -379,11 +394,27 @@ Style/CommentedKeyword:
|
||||
Exclude:
|
||||
- 'app/controllers/application_controller.rb'
|
||||
|
||||
# Offense count: 4
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, SingleLineConditionsOnly, IncludeTernaryExpressions.
|
||||
# SupportedStyles: assign_to_condition, assign_inside_condition
|
||||
Style/ConditionalAssignment:
|
||||
Exclude:
|
||||
- 'app/controllers/spree/api/products_controller.rb'
|
||||
- 'app/controllers/spree/api/taxons_controller.rb'
|
||||
- 'app/controllers/spree/api/variants_controller.rb'
|
||||
|
||||
# Offense count: 2
|
||||
Style/DateTime:
|
||||
Exclude:
|
||||
- 'lib/open_food_network/users_and_enterprises_report.rb'
|
||||
|
||||
# Offense count: 1
|
||||
# Cop supports --auto-correct.
|
||||
Style/EachWithObject:
|
||||
Exclude:
|
||||
- 'app/controllers/spree/api/base_controller.rb'
|
||||
|
||||
# Offense count: 5
|
||||
# Configuration parameters: EnforcedStyle.
|
||||
# SupportedStyles: annotated, template, unannotated
|
||||
@@ -393,7 +424,7 @@ Style/FormatStringToken:
|
||||
- 'lib/open_food_network/sales_tax_report.rb'
|
||||
- 'spec/models/enterprise_spec.rb'
|
||||
|
||||
# Offense count: 69
|
||||
# Offense count: 68
|
||||
# Configuration parameters: MinBodyLength.
|
||||
Style/GuardClause:
|
||||
Exclude:
|
||||
@@ -410,7 +441,9 @@ Style/GuardClause:
|
||||
- 'app/controllers/spree/admin/products_controller_decorator.rb'
|
||||
- 'app/controllers/spree/admin/resource_controller_decorator.rb'
|
||||
- 'app/controllers/spree/admin/variants_controller_decorator.rb'
|
||||
- 'app/controllers/spree/orders_controller_decorator.rb'
|
||||
- 'app/controllers/spree/api/base_controller.rb'
|
||||
- 'app/controllers/spree/checkout_controller.rb'
|
||||
- 'app/controllers/spree/orders_controller.rb'
|
||||
- 'app/controllers/spree/paypal_controller_decorator.rb'
|
||||
- 'app/jobs/products_cache_integrity_checker_job.rb'
|
||||
- 'app/models/enterprise.rb'
|
||||
@@ -434,12 +467,23 @@ Style/GuardClause:
|
||||
- 'spec/support/request/distribution_helper.rb'
|
||||
- 'spec/support/request/shop_workflow.rb'
|
||||
|
||||
# Offense count: 3
|
||||
# Offense count: 6
|
||||
# Cop supports --auto-correct.
|
||||
# Configuration parameters: EnforcedStyle, UseHashRocketsWithSymbolValues, PreferHashRocketsForNonAlnumEndingSymbols.
|
||||
# SupportedStyles: ruby19, hash_rockets, no_mixed_keys, ruby19_no_mixed_keys
|
||||
Style/HashSyntax:
|
||||
Exclude:
|
||||
- 'app/controllers/spree/api/base_controller.rb'
|
||||
- 'app/controllers/spree/checkout_controller.rb'
|
||||
- 'app/controllers/spree/orders_controller.rb'
|
||||
|
||||
# Offense count: 4
|
||||
Style/IfInsideElse:
|
||||
Exclude:
|
||||
- 'app/controllers/admin/column_preferences_controller.rb'
|
||||
- 'app/controllers/admin/variant_overrides_controller.rb'
|
||||
- 'app/controllers/spree/admin/products_controller_decorator.rb'
|
||||
- 'app/controllers/spree/api/taxons_controller.rb'
|
||||
|
||||
# Offense count: 1
|
||||
Style/MissingRespondToMissing:
|
||||
@@ -492,9 +536,10 @@ Style/RegexpLiteral:
|
||||
- 'spec/mailers/subscription_mailer_spec.rb'
|
||||
- 'spec/models/content_configuration_spec.rb'
|
||||
|
||||
# Offense count: 243
|
||||
# Offense count: 244
|
||||
Style/Send:
|
||||
Exclude:
|
||||
- 'app/controllers/spree/checkout_controller.rb'
|
||||
- 'app/models/spree/shipping_method_decorator.rb'
|
||||
- 'spec/controllers/admin/subscriptions_controller_spec.rb'
|
||||
- 'spec/controllers/checkout_controller_spec.rb'
|
||||
@@ -541,3 +586,9 @@ Style/Send:
|
||||
Style/StructInheritance:
|
||||
Exclude:
|
||||
- 'lib/open_food_network/enterprise_fee_applicator.rb'
|
||||
|
||||
# Offense count: 1
|
||||
# Cop supports --auto-correct.
|
||||
Style/UnlessElse:
|
||||
Exclude:
|
||||
- 'app/controllers/spree/api/variants_controller.rb'
|
||||
|
||||
@@ -1 +1 @@
|
||||
2.1.5
|
||||
2.1.9
|
||||
|
||||
@@ -6,7 +6,7 @@ RUN apt-get update && apt-get install -y curl git build-essential software-prope
|
||||
# Setup ENV variables
|
||||
ENV PATH /usr/local/src/rbenv/shims:/usr/local/src/rbenv/bin:$PATH
|
||||
ENV RBENV_ROOT /usr/local/src/rbenv
|
||||
ENV RUBY_VERSION 2.1.5
|
||||
ENV RUBY_VERSION 2.1.9
|
||||
ENV CONFIGURE_OPTS --disable-install-doc
|
||||
|
||||
# Rbenv & Ruby part
|
||||
|
||||
@@ -11,7 +11,7 @@ The following guides are located in the wiki and provide more OS-specific step-b
|
||||
### Dependencies
|
||||
|
||||
* Rails 3.2.x
|
||||
* Ruby 2.1.5
|
||||
* Ruby 2.1.9
|
||||
* PostgreSQL database
|
||||
* PhantomJS (for testing)
|
||||
* See Gemfile for a list of gems required
|
||||
|
||||
18
Gemfile
18
Gemfile
@@ -1,5 +1,5 @@
|
||||
source 'https://rubygems.org'
|
||||
ruby "2.1.5"
|
||||
ruby "2.1.9"
|
||||
git_source(:github) { |repo_name| "https://github.com/#{repo_name}.git" }
|
||||
|
||||
gem 'i18n', '~> 0.6.11'
|
||||
@@ -39,7 +39,7 @@ gem 'activemerchant', '~> 1.78'
|
||||
gem 'devise', '~> 2.2.5'
|
||||
gem 'devise-encryptable', '0.2.0'
|
||||
gem 'jwt', '~> 2.2'
|
||||
gem 'oauth2', '~> 1.4.1' # Used for Stripe Connect
|
||||
gem 'oauth2', '~> 1.4.2' # Used for Stripe Connect
|
||||
|
||||
gem 'daemons'
|
||||
gem 'delayed_job_active_record'
|
||||
@@ -49,6 +49,10 @@ gem 'delayed_job_web'
|
||||
# When merged, revert to upstream gem
|
||||
gem 'simple_form', github: 'RohanM/simple_form'
|
||||
|
||||
# Spree's default pagination gem (locked to the current version used by Spree)
|
||||
# We use it's methods in OFN code as well, so this is a direct dependency
|
||||
gem 'kaminari', '~> 0.14.1'
|
||||
|
||||
gem 'andand'
|
||||
gem 'angularjs-rails', '1.5.5'
|
||||
gem 'aws-sdk'
|
||||
@@ -81,7 +85,6 @@ gem 'paperclip', '~> 3.4.1'
|
||||
gem 'rack-rewrite'
|
||||
gem 'rack-ssl', require: 'rack/ssl'
|
||||
gem 'roadie-rails', '~> 1.1.1'
|
||||
gem 'skylight', '< 2.0'
|
||||
gem 'spinjs-rails'
|
||||
|
||||
gem 'combine_pdf'
|
||||
@@ -101,7 +104,10 @@ group :assets do
|
||||
gem 'coffee-rails', '~> 3.2.1'
|
||||
gem 'compass-rails'
|
||||
|
||||
gem 'therubyracer', '=0.12.0'
|
||||
gem 'mini_racer', '0.1.15'
|
||||
# Previously we found that libv8 6.7.288.46.1 breakis the compilation of mini_racer.
|
||||
# Now we see that we need to set the version explicitly. Nothing else depends on libv8.
|
||||
gem 'libv8', '6.3.292.48.1'
|
||||
|
||||
gem 'uglifier', '>= 1.0.3'
|
||||
|
||||
@@ -153,10 +159,6 @@ end
|
||||
group :development do
|
||||
gem 'byebug', '~> 9.0.0' # 9.1 requires ruby 2.2
|
||||
gem 'debugger-linecache'
|
||||
gem 'guard'
|
||||
gem 'guard-livereload'
|
||||
gem 'guard-rails'
|
||||
gem 'guard-rspec', '~> 4.7.3'
|
||||
gem 'listen', '3.0.8' # 3.1.0 requires ruby 2.2
|
||||
gem "newrelic_rpm", "~> 3.0"
|
||||
gem 'pry-byebug', '>= 3.4.3'
|
||||
|
||||
123
Gemfile.lock
123
Gemfile.lock
@@ -141,8 +141,8 @@ GEM
|
||||
activerecord (>= 3.2, < 5)
|
||||
acts_as_list (0.2.0)
|
||||
activerecord (>= 3.0)
|
||||
addressable (2.6.0)
|
||||
public_suffix (>= 2.0.2, < 4.0)
|
||||
addressable (2.7.0)
|
||||
public_suffix (>= 2.0.2, < 5.0)
|
||||
andand (1.3.3)
|
||||
angular-rails-templates (0.3.0)
|
||||
railties (>= 3.1)
|
||||
@@ -164,7 +164,7 @@ GEM
|
||||
bcrypt-ruby (3.1.5)
|
||||
bcrypt (>= 3.1.3)
|
||||
blockenspiel (0.5.0)
|
||||
bugsnag (6.11.1)
|
||||
bugsnag (6.12.1)
|
||||
concurrent-ruby (~> 1.0)
|
||||
builder (3.0.4)
|
||||
byebug (9.0.6)
|
||||
@@ -210,7 +210,7 @@ GEM
|
||||
compass (~> 1.0.0)
|
||||
sass-rails (< 5.1)
|
||||
sprockets (< 4.0)
|
||||
concurrent-ruby (1.1.4)
|
||||
concurrent-ruby (1.1.5)
|
||||
connection_pool (2.2.2)
|
||||
crack (0.4.3)
|
||||
safe_yaml (~> 1.0.0)
|
||||
@@ -223,7 +223,7 @@ GEM
|
||||
activerecord (>= 3.2.0, < 5.0)
|
||||
fog (~> 1.0)
|
||||
rails (>= 3.2.0, < 5.0)
|
||||
ddtrace (0.26.0)
|
||||
ddtrace (0.28.0)
|
||||
msgpack
|
||||
debugger-linecache (1.2.0)
|
||||
deface (1.0.2)
|
||||
@@ -231,10 +231,10 @@ GEM
|
||||
nokogiri (~> 1.6.0)
|
||||
polyglot
|
||||
rails (>= 3.1)
|
||||
delayed_job (4.1.5)
|
||||
activesupport (>= 3.0, < 5.3)
|
||||
delayed_job_active_record (4.1.3)
|
||||
activerecord (>= 3.0, < 5.3)
|
||||
delayed_job (4.1.8)
|
||||
activesupport (>= 3.0, < 6.1)
|
||||
delayed_job_active_record (4.1.4)
|
||||
activerecord (>= 3.0, < 6.1)
|
||||
delayed_job (>= 3.0, < 5)
|
||||
delayed_job_web (1.4.3)
|
||||
activerecord (> 3.0.0)
|
||||
@@ -252,9 +252,6 @@ GEM
|
||||
diffy (3.3.0)
|
||||
docile (1.3.2)
|
||||
dry-inflector (0.1.2)
|
||||
em-websocket (0.5.1)
|
||||
eventmachine (>= 0.12.9)
|
||||
http_parser.rb (~> 0.6.0)
|
||||
erubis (2.7.0)
|
||||
eventmachine (1.2.7)
|
||||
excon (0.62.0)
|
||||
@@ -432,34 +429,11 @@ GEM
|
||||
ruby-progressbar (~> 1.4)
|
||||
geocoder (1.1.8)
|
||||
gmaps4rails (1.5.6)
|
||||
guard (2.15.0)
|
||||
formatador (>= 0.2.4)
|
||||
listen (>= 2.7, < 4.0)
|
||||
lumberjack (>= 1.0.12, < 2.0)
|
||||
nenv (~> 0.1)
|
||||
notiffany (~> 0.0)
|
||||
pry (>= 0.9.12)
|
||||
shellany (~> 0.0)
|
||||
thor (>= 0.18.1)
|
||||
guard-compat (1.2.1)
|
||||
guard-livereload (2.5.2)
|
||||
em-websocket (~> 0.5)
|
||||
guard (~> 2.8)
|
||||
guard-compat (~> 1.0)
|
||||
multi_json (~> 1.8)
|
||||
guard-rails (0.7.2)
|
||||
guard (~> 2.11)
|
||||
guard-compat (~> 1.0)
|
||||
guard-rspec (4.7.3)
|
||||
guard (~> 2.1)
|
||||
guard-compat (~> 1.1)
|
||||
rspec (>= 2.99.0, < 4.0)
|
||||
haml (4.0.7)
|
||||
tilt
|
||||
hashdiff (1.0.0)
|
||||
highline (1.6.18)
|
||||
hike (1.2.3)
|
||||
http_parser.rb (0.6.0)
|
||||
httparty (0.16.2)
|
||||
multi_xml (>= 0.5.2)
|
||||
i18n (0.6.11)
|
||||
@@ -485,17 +459,16 @@ GEM
|
||||
actionpack (>= 3.0.0)
|
||||
activesupport (>= 3.0.0)
|
||||
kgio (2.11.2)
|
||||
knapsack (1.17.2)
|
||||
knapsack (1.18.0)
|
||||
rake
|
||||
launchy (2.4.3)
|
||||
addressable (~> 2.3)
|
||||
letter_opener (1.7.0)
|
||||
launchy (~> 2.2)
|
||||
libv8 (3.16.14.19)
|
||||
libv8 (6.3.292.48.1)
|
||||
listen (3.0.8)
|
||||
rb-fsevent (~> 0.9, >= 0.9.4)
|
||||
rb-inotify (~> 0.9, >= 0.9.7)
|
||||
lumberjack (1.0.13)
|
||||
mail (2.5.5)
|
||||
mime-types (~> 1.16)
|
||||
treetop (~> 1.4.8)
|
||||
@@ -503,6 +476,8 @@ GEM
|
||||
mime-types (1.25.1)
|
||||
mini_mime (1.0.1)
|
||||
mini_portile2 (2.1.0)
|
||||
mini_racer (0.1.15)
|
||||
libv8 (~> 6.3)
|
||||
momentjs-rails (2.20.1)
|
||||
railties (>= 3.1)
|
||||
money (5.1.1)
|
||||
@@ -511,17 +486,13 @@ GEM
|
||||
multi_json (1.13.1)
|
||||
multi_xml (0.6.0)
|
||||
multipart-post (2.1.1)
|
||||
nenv (0.3.0)
|
||||
net-http-persistent (3.0.1)
|
||||
net-http-persistent (3.1.0)
|
||||
connection_pool (~> 2.2)
|
||||
newrelic_rpm (3.18.1.330)
|
||||
nokogiri (1.6.8.1)
|
||||
mini_portile2 (~> 2.1.0)
|
||||
notiffany (0.1.1)
|
||||
nenv (~> 0.1)
|
||||
shellany (~> 0.0)
|
||||
oauth2 (1.4.1)
|
||||
faraday (>= 0.8, < 0.16.0)
|
||||
oauth2 (1.4.2)
|
||||
faraday (>= 0.8, < 2.0)
|
||||
jwt (>= 1.0, < 3.0)
|
||||
multi_json (~> 1.3)
|
||||
multi_xml (~> 0.5)
|
||||
@@ -610,7 +581,6 @@ GEM
|
||||
rdoc (3.12.2)
|
||||
json (~> 1.4)
|
||||
redcarpet (3.5.0)
|
||||
ref (2.0.0)
|
||||
request_store (1.4.1)
|
||||
rack (>= 1.4)
|
||||
roadie (3.4.0)
|
||||
@@ -626,29 +596,29 @@ GEM
|
||||
nokogiri
|
||||
roo (>= 2.0.0beta1, < 3)
|
||||
spreadsheet (> 0.9.0)
|
||||
rspec (3.8.0)
|
||||
rspec-core (~> 3.8.0)
|
||||
rspec-expectations (~> 3.8.0)
|
||||
rspec-mocks (~> 3.8.0)
|
||||
rspec-core (3.8.0)
|
||||
rspec-support (~> 3.8.0)
|
||||
rspec-expectations (3.8.2)
|
||||
rspec (3.9.0)
|
||||
rspec-core (~> 3.9.0)
|
||||
rspec-expectations (~> 3.9.0)
|
||||
rspec-mocks (~> 3.9.0)
|
||||
rspec-core (3.9.0)
|
||||
rspec-support (~> 3.9.0)
|
||||
rspec-expectations (3.9.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.8.0)
|
||||
rspec-mocks (3.8.0)
|
||||
rspec-support (~> 3.9.0)
|
||||
rspec-mocks (3.9.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.8.0)
|
||||
rspec-rails (3.8.2)
|
||||
rspec-support (~> 3.9.0)
|
||||
rspec-rails (3.9.0)
|
||||
actionpack (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
railties (>= 3.0)
|
||||
rspec-core (~> 3.8.0)
|
||||
rspec-expectations (~> 3.8.0)
|
||||
rspec-mocks (~> 3.8.0)
|
||||
rspec-support (~> 3.8.0)
|
||||
rspec-core (~> 3.9.0)
|
||||
rspec-expectations (~> 3.9.0)
|
||||
rspec-mocks (~> 3.9.0)
|
||||
rspec-support (~> 3.9.0)
|
||||
rspec-retry (0.6.1)
|
||||
rspec-core (> 3.3)
|
||||
rspec-support (3.8.0)
|
||||
rspec-support (3.9.0)
|
||||
rubocop (0.57.2)
|
||||
jaro_winkler (~> 1.5.1)
|
||||
parallel (~> 1.10)
|
||||
@@ -660,7 +630,7 @@ GEM
|
||||
ruby-ole (1.2.12.1)
|
||||
ruby-progressbar (1.10.1)
|
||||
ruby-rc4 (0.1.5)
|
||||
rubyzip (1.2.2)
|
||||
rubyzip (1.3.0)
|
||||
safe_yaml (1.0.5)
|
||||
sass (3.3.14)
|
||||
sass-rails (3.2.6)
|
||||
@@ -673,10 +643,9 @@ GEM
|
||||
selenium-webdriver (3.141.0)
|
||||
childprocess (~> 0.5)
|
||||
rubyzip (~> 1.2, >= 1.2.2)
|
||||
shellany (0.0.1)
|
||||
shoulda-matchers (2.8.0)
|
||||
activesupport (>= 3.0.0)
|
||||
simplecov (0.17.0)
|
||||
simplecov (0.17.1)
|
||||
docile (~> 1.1)
|
||||
json (>= 1.8, < 3)
|
||||
simplecov-html (~> 0.10.0)
|
||||
@@ -685,8 +654,6 @@ GEM
|
||||
rack (~> 1.4)
|
||||
rack-protection (~> 1.4)
|
||||
tilt (>= 1.3, < 3)
|
||||
skylight (1.7.2)
|
||||
activesupport (>= 3.0.0)
|
||||
spinjs-rails (1.4)
|
||||
rails (>= 3.1)
|
||||
spreadsheet (1.1.7)
|
||||
@@ -701,12 +668,9 @@ GEM
|
||||
tilt (~> 1.1, != 1.3.0)
|
||||
state_machine (1.2.0)
|
||||
stringex (1.5.1)
|
||||
stripe (4.19.0)
|
||||
stripe (4.24.0)
|
||||
faraday (~> 0.13)
|
||||
net-http-persistent (~> 3.0)
|
||||
therubyracer (0.12.0)
|
||||
libv8 (~> 3.16.14.0)
|
||||
ref
|
||||
thor (0.20.3)
|
||||
tilt (1.4.1)
|
||||
timecop (0.9.1)
|
||||
@@ -719,7 +683,7 @@ GEM
|
||||
railties (> 3.2.8, < 4.0.0)
|
||||
sprockets (>= 2.2.0)
|
||||
tzinfo (0.3.55)
|
||||
uglifier (4.1.20)
|
||||
uglifier (4.2.0)
|
||||
execjs (>= 0.3.0, < 3)
|
||||
unicode-display_width (1.3.2)
|
||||
unicorn (5.5.1)
|
||||
@@ -739,7 +703,7 @@ GEM
|
||||
nokogiri (~> 1.6)
|
||||
rubyzip (~> 1.0)
|
||||
selenium-webdriver (~> 3.0)
|
||||
webmock (3.6.2)
|
||||
webmock (3.7.6)
|
||||
addressable (>= 2.3.6)
|
||||
crack (>= 0.3.2)
|
||||
hashdiff (>= 0.4.0, < 2.0.0)
|
||||
@@ -796,10 +760,6 @@ DEPENDENCIES
|
||||
fuubar (~> 2.4.1)
|
||||
geocoder
|
||||
gmaps4rails
|
||||
guard
|
||||
guard-livereload
|
||||
guard-rails
|
||||
guard-rspec (~> 4.7.3)
|
||||
haml
|
||||
i18n (~> 0.6.11)
|
||||
i18n-js (~> 3.3.0)
|
||||
@@ -808,13 +768,16 @@ DEPENDENCIES
|
||||
jquery-rails (= 3.0.4)
|
||||
json_spec (~> 1.1.4)
|
||||
jwt (~> 2.2)
|
||||
kaminari (~> 0.14.1)
|
||||
knapsack
|
||||
letter_opener (>= 1.4.1)
|
||||
libv8 (= 6.3.292.48.1)
|
||||
listen (= 3.0.8)
|
||||
mini_racer (= 0.1.15)
|
||||
momentjs-rails
|
||||
newrelic_rpm (~> 3.0)
|
||||
nokogiri (>= 1.6.7.1)
|
||||
oauth2 (~> 1.4.1)
|
||||
oauth2 (~> 1.4.2)
|
||||
ofn-qz!
|
||||
oj
|
||||
order_management!
|
||||
@@ -842,7 +805,6 @@ DEPENDENCIES
|
||||
shoulda-matchers
|
||||
simple_form!
|
||||
simplecov
|
||||
skylight (< 2.0)
|
||||
spinjs-rails
|
||||
spree_api!
|
||||
spree_backend!
|
||||
@@ -852,7 +814,6 @@ DEPENDENCIES
|
||||
spring (= 1.7.2)
|
||||
spring-commands-rspec
|
||||
stripe
|
||||
therubyracer (= 0.12.0)
|
||||
timecop
|
||||
truncate_html
|
||||
turbo-sprockets-rails3
|
||||
@@ -867,7 +828,7 @@ DEPENDENCIES
|
||||
wkhtmltopdf-binary
|
||||
|
||||
RUBY VERSION
|
||||
ruby 2.1.5p273
|
||||
ruby 2.1.9p490
|
||||
|
||||
BUNDLED WITH
|
||||
1.17.2
|
||||
|
||||
11
Guardfile
11
Guardfile
@@ -1,11 +0,0 @@
|
||||
# A sample Guardfile
|
||||
# More info at https://github.com/guard/guard#readme
|
||||
|
||||
guard 'livereload' do
|
||||
watch(%r{app/views/.+\.(erb|haml|slim)$})
|
||||
watch(%r{app/helpers/.+\.rb})
|
||||
watch(%r{public/.+\.(css|js|html)})
|
||||
|
||||
# Rails Assets Pipeline
|
||||
watch(%r{(app|vendor)(/assets/\w+/(.+\.(css|js|html|png|jpg))).*}) { |m| "/assets/#{m[3]}" }
|
||||
end
|
||||
@@ -1,6 +1,5 @@
|
||||
[](https://semaphoreci.com/openfoodfoundation/openfoodnetwork-2)
|
||||
[](https://codeclimate.com/github/openfoodfoundation/openfoodnetwork)
|
||||
[](https://oss.skylight.io/app/applications/EiXQ6sSKij8y)
|
||||
|
||||
# Open Food Network
|
||||
|
||||
@@ -36,7 +35,7 @@ We use [BrowserStack](https://www.browserstack.com/) as a manual testing tool. B
|
||||
Copyright (c) 2012 - 2019 Open Food Foundation, released under the AGPL licence.
|
||||
|
||||
[survey]: https://docs.google.com/a/eaterprises.com.au/forms/d/1zxR5vSiU9CigJ9cEaC8-eJLgYid8CR8er7PPH9Mc-30/edit#
|
||||
[slack-invite]: https://openfoodnetwork.org/slack-invite
|
||||
[slack-invite]: https://join.slack.com/t/openfoodnetwork/shared_invite/enQtNzY3NDEwNzM2MDM0LWFmNGRhNDUwYzNmNWNkYmFkMzgxNDg1OTg1ODNjNWY4Y2FhNDIwNmE4ZWI0OThiMGNmZjFkODczNGZiYTJmNWI
|
||||
[contributor-guide]: https://ofn-user-guide.gitbook.io/ofn-contributor-guide/who-are-we
|
||||
[ofn-install]: https://github.com/openfoodfoundation/ofn-install
|
||||
[super-admin-guide]: https://ofn-user-guide.gitbook.io/ofn-super-admin-guide
|
||||
|
||||
@@ -1,267 +1,287 @@
|
||||
angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout, $http, $window, BulkProducts, DisplayProperties, dataFetcher, DirtyProducts, VariantUnitManager, StatusMessage, producers, Taxons, SpreeApiAuth, Columns, tax_categories) ->
|
||||
$scope.loading = true
|
||||
$scope.loadingAllPages = true
|
||||
angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout, $filter, $http, $window, BulkProducts, DisplayProperties, DirtyProducts, VariantUnitManager, StatusMessage, producers, Taxons, SpreeApiAuth, Columns, tax_categories, RequestMonitor) ->
|
||||
$scope.StatusMessage = StatusMessage
|
||||
|
||||
$scope.StatusMessage = StatusMessage
|
||||
$scope.columns = Columns.columns
|
||||
|
||||
$scope.columns = Columns.columns
|
||||
$scope.variant_unit_options = VariantUnitManager.variantUnitOptions()
|
||||
|
||||
$scope.variant_unit_options = VariantUnitManager.variantUnitOptions()
|
||||
$scope.RequestMonitor = RequestMonitor
|
||||
$scope.pagination = BulkProducts.pagination
|
||||
$scope.per_page_options = [
|
||||
{id: 15, name: t('js.admin.orders.index.per_page', results: 15)},
|
||||
{id: 50, name: t('js.admin.orders.index.per_page', results: 50)},
|
||||
{id: 100, name: t('js.admin.orders.index.per_page', results: 100)}
|
||||
]
|
||||
|
||||
$scope.filterableColumns = [
|
||||
{ name: t("label_producers"), db_column: "producer_name" },
|
||||
{ name: t("name"), db_column: "name" }
|
||||
]
|
||||
$scope.filterableColumns = [
|
||||
{ name: t("label_producers"), db_column: "producer_name" },
|
||||
{ name: t("name"), db_column: "name" }
|
||||
]
|
||||
|
||||
$scope.filterTypes = [
|
||||
{ name: t("equals"), predicate: "eq" },
|
||||
{ name: t("contains"), predicate: "cont" }
|
||||
]
|
||||
$scope.filterTypes = [
|
||||
{ name: t("equals"), predicate: "eq" },
|
||||
{ name: t("contains"), predicate: "cont" }
|
||||
]
|
||||
|
||||
$scope.optionTabs =
|
||||
filters: { title: t("filter_products"), visible: false }
|
||||
$scope.optionTabs =
|
||||
filters: { title: t("filter_products"), visible: false }
|
||||
|
||||
$scope.producers = producers
|
||||
$scope.taxons = Taxons.all
|
||||
$scope.tax_categories = tax_categories
|
||||
$scope.producerFilter = ""
|
||||
$scope.categoryFilter = ""
|
||||
$scope.importDateFilter = ""
|
||||
$scope.page = 1
|
||||
$scope.per_page = 15
|
||||
$scope.products = BulkProducts.products
|
||||
$scope.query = ""
|
||||
$scope.DisplayProperties = DisplayProperties
|
||||
|
||||
$scope.initialise = ->
|
||||
SpreeApiAuth.authorise()
|
||||
.then ->
|
||||
$scope.spree_api_key_ok = true
|
||||
$scope.fetchProducts()
|
||||
.catch (message) ->
|
||||
$scope.api_error_msg = message
|
||||
|
||||
$scope.$watchCollection '[query, producerFilter, categoryFilter, importDateFilter, per_page]', ->
|
||||
$scope.page = 1 # Reset page when changing filters for new search
|
||||
|
||||
$scope.changePage = (newPage) ->
|
||||
$scope.page = newPage
|
||||
$scope.fetchProducts()
|
||||
|
||||
$scope.fetchProducts = ->
|
||||
removeClearedValues()
|
||||
params = {
|
||||
'q[name_cont]': $scope.query,
|
||||
'q[supplier_id_eq]': $scope.producerFilter,
|
||||
'q[primary_taxon_id_eq]': $scope.categoryFilter,
|
||||
import_date: $scope.importDateFilter,
|
||||
page: $scope.page,
|
||||
per_page: $scope.per_page
|
||||
}
|
||||
RequestMonitor.load(BulkProducts.fetch(params).$promise).then ->
|
||||
$scope.resetProducts()
|
||||
|
||||
removeClearedValues = ->
|
||||
delete $scope.producerFilter if $scope.producerFilter == "0"
|
||||
delete $scope.categoryFilter if $scope.categoryFilter == "0"
|
||||
delete $scope.importDateFilter if $scope.importDateFilter == "0"
|
||||
|
||||
$timeout ->
|
||||
if $scope.showLatestImport
|
||||
$scope.importDateFilter = $scope.importDates[1].id
|
||||
|
||||
$scope.resetProducts = ->
|
||||
DirtyProducts.clear()
|
||||
StatusMessage.clear()
|
||||
|
||||
$scope.updateOnHand = (product) ->
|
||||
on_demand_variants = []
|
||||
if product.variants
|
||||
on_demand_variants = (variant for id, variant of product.variants when variant.on_demand)
|
||||
|
||||
unless product.on_demand || on_demand_variants.length > 0
|
||||
product.on_hand = $scope.onHand(product)
|
||||
|
||||
|
||||
$scope.producers = producers
|
||||
$scope.taxons = Taxons.all
|
||||
$scope.tax_categories = tax_categories
|
||||
$scope.filterProducers = [{id: "0", name: ""}].concat $scope.producers
|
||||
$scope.filterTaxons = [{id: "0", name: ""}].concat $scope.taxons
|
||||
$scope.onHand = (product) ->
|
||||
onHand = 0
|
||||
if product.hasOwnProperty("variants") and product.variants instanceof Object
|
||||
for id, variant of product.variants
|
||||
onHand = onHand + parseInt(if variant.on_hand > 0 then variant.on_hand else 0)
|
||||
else
|
||||
onHand = "error"
|
||||
onHand
|
||||
|
||||
$scope.shiftTab = (tab) ->
|
||||
$scope.visibleTab.visible = false unless $scope.visibleTab == tab || $scope.visibleTab == undefined
|
||||
tab.visible = !tab.visible
|
||||
$scope.visibleTab = tab
|
||||
|
||||
$scope.resetSelectFilters = ->
|
||||
$scope.query = ""
|
||||
$scope.producerFilter = "0"
|
||||
$scope.categoryFilter = "0"
|
||||
$scope.importDateFilter = "0"
|
||||
$scope.products = BulkProducts.products
|
||||
$scope.filteredProducts = []
|
||||
$scope.currentFilters = []
|
||||
$scope.limit = 15
|
||||
$scope.query = ""
|
||||
$scope.DisplayProperties = DisplayProperties
|
||||
|
||||
$scope.initialise = ->
|
||||
SpreeApiAuth.authorise()
|
||||
.then ->
|
||||
$scope.spree_api_key_ok = true
|
||||
$scope.fetchProducts()
|
||||
.catch (message) ->
|
||||
$scope.api_error_msg = message
|
||||
|
||||
$scope.$watchCollection '[query, producerFilter, categoryFilter, importDateFilter]', ->
|
||||
$scope.limit = 15 # Reset limit whenever searching
|
||||
|
||||
$scope.fetchProducts = ->
|
||||
$scope.loading = true
|
||||
$scope.loadingAllPages = true
|
||||
BulkProducts.fetch($scope.currentFilters, ->
|
||||
$scope.loadingAllPages = false
|
||||
).then ->
|
||||
$scope.resetProducts()
|
||||
$scope.loading = false
|
||||
|
||||
$timeout ->
|
||||
if $scope.showLatestImport
|
||||
$scope.importDateFilter = $scope.importDates[1].id
|
||||
|
||||
$scope.resetProducts = ->
|
||||
DirtyProducts.clear()
|
||||
StatusMessage.clear()
|
||||
|
||||
$scope.updateOnHand = (product) ->
|
||||
on_demand_variants = []
|
||||
if product.variants
|
||||
on_demand_variants = (variant for id, variant of product.variants when variant.on_demand)
|
||||
|
||||
unless product.on_demand || on_demand_variants.length > 0
|
||||
product.on_hand = $scope.onHand(product)
|
||||
$scope.editWarn = (product, variant) ->
|
||||
if (DirtyProducts.count() > 0 and confirm(t("unsaved_changes_confirmation"))) or (DirtyProducts.count() == 0)
|
||||
window.location = "/admin/products/" + product.permalink_live + ((if variant then "/variants/" + variant.id else "")) + "/edit"
|
||||
|
||||
|
||||
$scope.onHand = (product) ->
|
||||
onHand = 0
|
||||
if product.hasOwnProperty("variants") and product.variants instanceof Object
|
||||
for id, variant of product.variants
|
||||
onHand = onHand + parseInt(if variant.on_hand > 0 then variant.on_hand else 0)
|
||||
else
|
||||
onHand = "error"
|
||||
onHand
|
||||
$scope.toggleShowAllVariants = ->
|
||||
showVariants = !DisplayProperties.showVariants 0
|
||||
$scope.products.forEach (product) ->
|
||||
DisplayProperties.setShowVariants product.id, showVariants
|
||||
DisplayProperties.setShowVariants 0, showVariants
|
||||
|
||||
$scope.shiftTab = (tab) ->
|
||||
$scope.visibleTab.visible = false unless $scope.visibleTab == tab || $scope.visibleTab == undefined
|
||||
tab.visible = !tab.visible
|
||||
$scope.visibleTab = tab
|
||||
|
||||
$scope.resetSelectFilters = ->
|
||||
$scope.query = ""
|
||||
$scope.producerFilter = "0"
|
||||
$scope.categoryFilter = "0"
|
||||
$scope.importDateFilter = "0"
|
||||
|
||||
$scope.editWarn = (product, variant) ->
|
||||
if (DirtyProducts.count() > 0 and confirm(t("unsaved_changes_confirmation"))) or (DirtyProducts.count() == 0)
|
||||
window.location = "/admin/products/" + product.permalink_live + ((if variant then "/variants/" + variant.id else "")) + "/edit"
|
||||
$scope.addVariant = (product) ->
|
||||
product.variants.push
|
||||
id: $scope.nextVariantId()
|
||||
unit_value: null
|
||||
unit_description: null
|
||||
on_demand: false
|
||||
display_as: null
|
||||
display_name: null
|
||||
on_hand: null
|
||||
price: null
|
||||
DisplayProperties.setShowVariants product.id, true
|
||||
|
||||
|
||||
$scope.toggleShowAllVariants = ->
|
||||
showVariants = !DisplayProperties.showVariants 0
|
||||
$scope.filteredProducts.forEach (product) ->
|
||||
DisplayProperties.setShowVariants product.id, showVariants
|
||||
DisplayProperties.setShowVariants 0, showVariants
|
||||
$scope.nextVariantId = ->
|
||||
$scope.variantIdCounter = 0 unless $scope.variantIdCounter?
|
||||
$scope.variantIdCounter -= 1
|
||||
$scope.variantIdCounter
|
||||
|
||||
$scope.addVariant = (product) ->
|
||||
product.variants.push
|
||||
id: $scope.nextVariantId()
|
||||
unit_value: null
|
||||
unit_description: null
|
||||
on_demand: false
|
||||
display_as: null
|
||||
display_name: null
|
||||
on_hand: null
|
||||
price: null
|
||||
DisplayProperties.setShowVariants product.id, true
|
||||
|
||||
|
||||
$scope.nextVariantId = ->
|
||||
$scope.variantIdCounter = 0 unless $scope.variantIdCounter?
|
||||
$scope.variantIdCounter -= 1
|
||||
$scope.variantIdCounter
|
||||
|
||||
$scope.deleteProduct = (product) ->
|
||||
if confirm("Are you sure?")
|
||||
$http(
|
||||
method: "DELETE"
|
||||
url: "/api/products/" + product.id + "/soft_delete"
|
||||
).success (data) ->
|
||||
$scope.products.splice $scope.products.indexOf(product), 1
|
||||
DirtyProducts.deleteProduct product.id
|
||||
$scope.displayDirtyProducts()
|
||||
|
||||
|
||||
$scope.deleteVariant = (product, variant) ->
|
||||
if product.variants.length > 1
|
||||
if !$scope.variantSaved(variant)
|
||||
$scope.removeVariant(product, variant)
|
||||
else
|
||||
if confirm(t("are_you_sure"))
|
||||
$http(
|
||||
method: "DELETE"
|
||||
url: "/api/products/" + product.permalink_live + "/variants/" + variant.id + "/soft_delete"
|
||||
).success (data) ->
|
||||
$scope.removeVariant(product, variant)
|
||||
else
|
||||
alert(t("delete_product_variant"))
|
||||
|
||||
$scope.removeVariant = (product, variant) ->
|
||||
product.variants.splice product.variants.indexOf(variant), 1
|
||||
DirtyProducts.deleteVariant product.id, variant.id
|
||||
$scope.displayDirtyProducts()
|
||||
|
||||
|
||||
$scope.cloneProduct = (product) ->
|
||||
BulkProducts.cloneProduct product
|
||||
|
||||
$scope.hasVariants = (product) ->
|
||||
product.variants.length > 0
|
||||
|
||||
|
||||
$scope.hasUnit = (product) ->
|
||||
product.variant_unit_with_scale?
|
||||
|
||||
|
||||
$scope.variantSaved = (variant) ->
|
||||
variant.hasOwnProperty('id') && variant.id > 0
|
||||
|
||||
|
||||
$scope.hasOnDemandVariants = (product) ->
|
||||
(variant for id, variant of product.variants when variant.on_demand).length > 0
|
||||
|
||||
|
||||
$scope.submitProducts = ->
|
||||
# Pack pack $scope.products, so they will match the list returned from the server,
|
||||
# then pack $scope.dirtyProducts, ensuring that the correct product info is sent to the server.
|
||||
$scope.packProduct product for id, product of $scope.products
|
||||
$scope.packProduct product for id, product of DirtyProducts.all()
|
||||
|
||||
productsToSubmit = filterSubmitProducts(DirtyProducts.all())
|
||||
if productsToSubmit.length > 0
|
||||
$scope.updateProducts productsToSubmit # Don't submit an empty list
|
||||
else
|
||||
StatusMessage.display 'alert', t("products_change")
|
||||
|
||||
|
||||
$scope.updateProducts = (productsToSubmit) ->
|
||||
$scope.displayUpdating()
|
||||
$scope.deleteProduct = (product) ->
|
||||
if confirm("Are you sure?")
|
||||
$http(
|
||||
method: "POST"
|
||||
url: "/admin/products/bulk_update"
|
||||
data:
|
||||
products: productsToSubmit
|
||||
filters: $scope.currentFilters
|
||||
).success((data) ->
|
||||
DirtyProducts.clear()
|
||||
BulkProducts.updateVariantLists(data.products || [])
|
||||
$timeout -> $scope.displaySuccess()
|
||||
).error (data, status) ->
|
||||
if status == 400 && data.errors? && data.errors.length > 0
|
||||
errors = error + "\n" for error in data.errors
|
||||
alert t("products_update_error") + "\n" + errors
|
||||
$scope.displayFailure t("products_update_error")
|
||||
else
|
||||
$scope.displayFailure t("products_update_error_data") + status
|
||||
method: "DELETE"
|
||||
url: "/api/products/" + product.id + "/soft_delete"
|
||||
).success (data) ->
|
||||
$scope.products.splice $scope.products.indexOf(product), 1
|
||||
DirtyProducts.deleteProduct product.id
|
||||
$scope.displayDirtyProducts()
|
||||
|
||||
$scope.cancel = (destination) ->
|
||||
$window.location = destination
|
||||
|
||||
$scope.packProduct = (product) ->
|
||||
if product.variant_unit_with_scale
|
||||
match = product.variant_unit_with_scale.match(/^([^_]+)_([\d\.]+)$/)
|
||||
if match
|
||||
product.variant_unit = match[1]
|
||||
product.variant_unit_scale = parseFloat(match[2])
|
||||
else
|
||||
product.variant_unit = product.variant_unit_with_scale
|
||||
product.variant_unit_scale = null
|
||||
$scope.deleteVariant = (product, variant) ->
|
||||
if product.variants.length > 1
|
||||
if !$scope.variantSaved(variant)
|
||||
$scope.removeVariant(product, variant)
|
||||
else
|
||||
product.variant_unit = product.variant_unit_scale = null
|
||||
if confirm(t("are_you_sure"))
|
||||
$http(
|
||||
method: "DELETE"
|
||||
url: "/api/products/" + product.permalink_live + "/variants/" + variant.id + "/soft_delete"
|
||||
).success (data) ->
|
||||
$scope.removeVariant(product, variant)
|
||||
else
|
||||
alert(t("delete_product_variant"))
|
||||
|
||||
$scope.packVariant product, product.master if product.master
|
||||
|
||||
if product.variants
|
||||
for id, variant of product.variants
|
||||
$scope.packVariant product, variant
|
||||
$scope.removeVariant = (product, variant) ->
|
||||
product.variants.splice product.variants.indexOf(variant), 1
|
||||
DirtyProducts.deleteVariant product.id, variant.id
|
||||
$scope.displayDirtyProducts()
|
||||
|
||||
|
||||
$scope.packVariant = (product, variant) ->
|
||||
if variant.hasOwnProperty("unit_value_with_description")
|
||||
match = variant.unit_value_with_description.match(/^([\d\.]+(?= |$)|)( |)(.*)$/)
|
||||
if match
|
||||
product = BulkProducts.find product.id
|
||||
variant.unit_value = parseFloat(match[1])
|
||||
variant.unit_value = null if isNaN(variant.unit_value)
|
||||
variant.unit_value *= product.variant_unit_scale if variant.unit_value && product.variant_unit_scale
|
||||
variant.unit_description = match[3]
|
||||
$scope.cloneProduct = (product) ->
|
||||
BulkProducts.cloneProduct product
|
||||
|
||||
$scope.incrementLimit = ->
|
||||
if $scope.limit < $scope.products.length
|
||||
$scope.limit = $scope.limit + 5
|
||||
$scope.hasVariants = (product) ->
|
||||
product.variants.length > 0
|
||||
|
||||
|
||||
$scope.displayUpdating = ->
|
||||
StatusMessage.display 'progress', t("saving")
|
||||
$scope.hasUnit = (product) ->
|
||||
product.variant_unit_with_scale?
|
||||
|
||||
|
||||
$scope.displaySuccess = ->
|
||||
StatusMessage.display 'success',t("products_changes_saved")
|
||||
$scope.bulk_product_form.$setPristine()
|
||||
$scope.variantSaved = (variant) ->
|
||||
variant.hasOwnProperty('id') && variant.id > 0
|
||||
|
||||
|
||||
$scope.displayFailure = (failMessage) ->
|
||||
StatusMessage.display 'failure', t("products_update_error_msg") + "#{failMessage}"
|
||||
$scope.hasOnDemandVariants = (product) ->
|
||||
(variant for id, variant of product.variants when variant.on_demand).length > 0
|
||||
|
||||
|
||||
$scope.displayDirtyProducts = ->
|
||||
count = DirtyProducts.count()
|
||||
switch count
|
||||
when 0 then StatusMessage.clear()
|
||||
when 1 then StatusMessage.display 'notice', t("one_product_unsaved")
|
||||
else StatusMessage.display 'notice', t("products_unsaved", n: count)
|
||||
$scope.submitProducts = ->
|
||||
# Pack pack $scope.products, so they will match the list returned from the server,
|
||||
# then pack $scope.dirtyProducts, ensuring that the correct product info is sent to the server.
|
||||
$scope.packProduct product for id, product of $scope.products
|
||||
$scope.packProduct product for id, product of DirtyProducts.all()
|
||||
|
||||
productsToSubmit = filterSubmitProducts(DirtyProducts.all())
|
||||
if productsToSubmit.length > 0
|
||||
$scope.updateProducts productsToSubmit # Don't submit an empty list
|
||||
else
|
||||
StatusMessage.display 'alert', t("products_change")
|
||||
|
||||
|
||||
$scope.updateProducts = (productsToSubmit) ->
|
||||
$scope.displayUpdating()
|
||||
$http(
|
||||
method: "POST"
|
||||
url: "/admin/products/bulk_update"
|
||||
data:
|
||||
products: productsToSubmit
|
||||
filters:
|
||||
'q[name_cont]': $scope.query
|
||||
'q[supplier_id_eq]': $scope.producerFilter
|
||||
'q[primary_taxon_id_eq]': $scope.categoryFilter
|
||||
import_date: $scope.importDateFilter
|
||||
page: $scope.page
|
||||
per_page: $scope.per_page
|
||||
).success((data) ->
|
||||
DirtyProducts.clear()
|
||||
BulkProducts.updateVariantLists(data.products || [])
|
||||
$timeout -> $scope.displaySuccess()
|
||||
).error (data, status) ->
|
||||
if status == 400 && data.errors? && data.errors.length > 0
|
||||
errors = error + "\n" for error in data.errors
|
||||
alert t("products_update_error") + "\n" + errors
|
||||
$scope.displayFailure t("products_update_error")
|
||||
else
|
||||
$scope.displayFailure t("products_update_error_data") + status
|
||||
|
||||
$scope.cancel = (destination) ->
|
||||
$window.location = destination
|
||||
|
||||
$scope.packProduct = (product) ->
|
||||
if product.variant_unit_with_scale
|
||||
match = product.variant_unit_with_scale.match(/^([^_]+)_([\d\.]+)$/)
|
||||
if match
|
||||
product.variant_unit = match[1]
|
||||
product.variant_unit_scale = parseFloat(match[2])
|
||||
else
|
||||
product.variant_unit = product.variant_unit_with_scale
|
||||
product.variant_unit_scale = null
|
||||
else
|
||||
product.variant_unit = product.variant_unit_scale = null
|
||||
|
||||
$scope.packVariant product, product.master if product.master
|
||||
|
||||
if product.variants
|
||||
for id, variant of product.variants
|
||||
$scope.packVariant product, variant
|
||||
|
||||
|
||||
$scope.packVariant = (product, variant) ->
|
||||
if variant.hasOwnProperty("unit_value_with_description")
|
||||
match = variant.unit_value_with_description.match(/^([\d\.]+(?= |$)|)( |)(.*)$/)
|
||||
if match
|
||||
product = BulkProducts.find product.id
|
||||
variant.unit_value = parseFloat(match[1])
|
||||
variant.unit_value = null if isNaN(variant.unit_value)
|
||||
variant.unit_value *= product.variant_unit_scale if variant.unit_value && product.variant_unit_scale
|
||||
variant.unit_description = match[3]
|
||||
|
||||
$scope.incrementLimit = ->
|
||||
if $scope.limit < $scope.products.length
|
||||
$scope.limit = $scope.limit + 5
|
||||
|
||||
|
||||
$scope.displayUpdating = ->
|
||||
StatusMessage.display 'progress', t("saving")
|
||||
|
||||
|
||||
$scope.displaySuccess = ->
|
||||
StatusMessage.display 'success',t("products_changes_saved")
|
||||
$scope.bulk_product_form.$setPristine()
|
||||
|
||||
|
||||
$scope.displayFailure = (failMessage) ->
|
||||
StatusMessage.display 'failure', t("products_update_error_msg") + "#{failMessage}"
|
||||
|
||||
|
||||
$scope.displayDirtyProducts = ->
|
||||
count = DirtyProducts.count()
|
||||
switch count
|
||||
when 0 then StatusMessage.clear()
|
||||
when 1 then StatusMessage.display 'notice', t("one_product_unsaved")
|
||||
else StatusMessage.display 'notice', t("products_unsaved", n: count)
|
||||
|
||||
|
||||
filterSubmitProducts = (productsToFilter) ->
|
||||
|
||||
@@ -23,7 +23,7 @@ angular.module("admin.orders").controller "ordersCtrl", ($scope, RequestMonitor,
|
||||
|
||||
$scope.fetchResults = (page=1) ->
|
||||
$scope.resetSelected()
|
||||
Orders.index({
|
||||
params = {
|
||||
'q[completed_at_lt]': $scope['q']['completed_at_lt'],
|
||||
'q[completed_at_gt]': $scope['q']['completed_at_gt'],
|
||||
'q[state_eq]': $scope['q']['state_eq'],
|
||||
@@ -39,7 +39,8 @@ angular.module("admin.orders").controller "ordersCtrl", ($scope, RequestMonitor,
|
||||
'q[s]': $scope.sorting || 'completed_at desc',
|
||||
per_page: $scope.per_page,
|
||||
page: page
|
||||
})
|
||||
}
|
||||
RequestMonitor.load(Orders.index(params).$promise)
|
||||
|
||||
$scope.resetSelected = ->
|
||||
$scope.selected_orders.length = 0
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
angular.module("admin.products").directive "setOnDemand", ->
|
||||
link: (scope, element, attr) ->
|
||||
onHand = element.context.querySelector("#variant_on_hand")
|
||||
onDemand = element.context.querySelector("#variant_on_demand")
|
||||
|
||||
disableOnHandIfOnDemand = ->
|
||||
if onDemand.checked
|
||||
onHand.disabled = 'disabled'
|
||||
onHand.dataStock = onHand.value
|
||||
onHand.value = t('admin.products.variants.infinity')
|
||||
|
||||
disableOnHandIfOnDemand()
|
||||
|
||||
onDemand.addEventListener 'change', (event) ->
|
||||
disableOnHandIfOnDemand()
|
||||
|
||||
if !onDemand.checked
|
||||
onHand.removeAttribute('disabled')
|
||||
onHand.value = onHand.dataStock
|
||||
@@ -0,0 +1,6 @@
|
||||
angular.module("admin.resources").factory 'ProductResource', ($resource) ->
|
||||
$resource('/admin/product/:id/:action.json', {}, {
|
||||
'index':
|
||||
url: '/api/products/bulk_products.json'
|
||||
method: 'GET'
|
||||
})
|
||||
@@ -1,15 +1,13 @@
|
||||
angular.module("ofn.admin").factory "BulkProducts", (PagedFetcher, dataFetcher, $http) ->
|
||||
angular.module("ofn.admin").factory "BulkProducts", (ProductResource, dataFetcher, $http) ->
|
||||
new class BulkProducts
|
||||
products: []
|
||||
pagination: {}
|
||||
|
||||
fetch: (filters, onComplete) ->
|
||||
queryString = filters.reduce (qs,f) ->
|
||||
return qs + "q[#{f.property.db_column}_#{f.predicate.predicate}]=#{f.value};"
|
||||
, ""
|
||||
|
||||
url = "/api/products/bulk_products?page=::page::;per_page=20;#{queryString}"
|
||||
processData = (data) => @addProducts data.products
|
||||
PagedFetcher.fetch url, processData, onComplete
|
||||
fetch: (params) ->
|
||||
ProductResource.index params, (data) =>
|
||||
@products.length = 0
|
||||
@addProducts data.products
|
||||
angular.extend(@pagination, data.pagination)
|
||||
|
||||
cloneProduct: (product) ->
|
||||
$http.post("/api/products/" + product.id + "/clone").success (data) =>
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
@API_DATETIME_FORMAT = "YYYY-MM-DD HH:mm:SS Z"
|
||||
|
||||
Darkswarm.filter "date_in_words", ->
|
||||
(date) ->
|
||||
moment(date).fromNow()
|
||||
(date, dateFormat) ->
|
||||
dateFormat ?= @API_DATETIME_FORMAT
|
||||
moment(date, dateFormat).fromNow()
|
||||
|
||||
Darkswarm.filter "sensible_timeframe", (date_in_wordsFilter)->
|
||||
(date) ->
|
||||
if moment().add(2, 'days') < moment(date)
|
||||
(date, dateFormat) ->
|
||||
dateFormat ?= @API_DATETIME_FORMAT
|
||||
|
||||
if moment().add(2, 'days') < moment(date, dateFormat)
|
||||
t 'orders_open'
|
||||
else
|
||||
t('closing') + date_in_wordsFilter(date)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
.select2-container {
|
||||
.select2-choice {
|
||||
.select2-search-choice-close {
|
||||
display: none;
|
||||
display: none !important;
|
||||
}
|
||||
.select2-arrow {
|
||||
width: 22px;
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
module Api
|
||||
class OrdersController < BaseController
|
||||
def show
|
||||
authorize! :read, order
|
||||
render json: order, serializer: Api::OrderDetailedSerializer, current_order: order
|
||||
end
|
||||
|
||||
def index
|
||||
authorize! :admin, Spree::Order
|
||||
|
||||
@@ -19,5 +24,12 @@ module Api
|
||||
each_serializer: Api::Admin::OrderSerializer
|
||||
)
|
||||
end
|
||||
|
||||
def order
|
||||
@order ||= Spree::Order.
|
||||
where(number: params[:id]).
|
||||
includes(line_items: { variant: [:product, :stock_items, :default_price] }).
|
||||
first!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
146
app/controllers/api/products_controller.rb
Normal file
146
app/controllers/api/products_controller.rb
Normal file
@@ -0,0 +1,146 @@
|
||||
require 'open_food_network/permissions'
|
||||
|
||||
module Api
|
||||
class ProductsController < Api::BaseController
|
||||
respond_to :json
|
||||
DEFAULT_PAGE = 1
|
||||
DEFAULT_PER_PAGE = 15
|
||||
|
||||
skip_authorization_check only: [:show, :bulk_products, :overridable]
|
||||
|
||||
def show
|
||||
@product = find_product(params[:id])
|
||||
render json: @product, serializer: Api::Admin::ProductSerializer
|
||||
end
|
||||
|
||||
def create
|
||||
authorize! :create, Spree::Product
|
||||
params[:product][:available_on] ||= Time.zone.now
|
||||
@product = Spree::Product.new(params[:product])
|
||||
begin
|
||||
if @product.save
|
||||
render json: @product, serializer: Api::Admin::ProductSerializer, status: 201
|
||||
else
|
||||
invalid_resource!(@product)
|
||||
end
|
||||
rescue ActiveRecord::RecordNotUnique
|
||||
@product.permalink = nil
|
||||
retry
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
authorize! :update, Spree::Product
|
||||
@product = find_product(params[:id])
|
||||
if @product.update_attributes(params[:product])
|
||||
render json: @product, serializer: Api::Admin::ProductSerializer, status: 200
|
||||
else
|
||||
invalid_resource!(@product)
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
authorize! :delete, Spree::Product
|
||||
@product = find_product(params[:id])
|
||||
@product.update_attribute(:deleted_at, Time.zone.now)
|
||||
@product.variants_including_master.update_all(deleted_at: Time.zone.now)
|
||||
render json: @product, serializer: Api::Admin::ProductSerializer, status: 204
|
||||
end
|
||||
|
||||
# TODO: This should be named 'managed'. Is the action above used? Maybe we should remove it.
|
||||
def bulk_products
|
||||
product_query = OpenFoodNetwork::Permissions.new(current_api_user).
|
||||
editable_products.merge(product_scope)
|
||||
|
||||
if params[:import_date].present?
|
||||
product_query = product_query.imported_on(params[:import_date]).group_by_products_id
|
||||
end
|
||||
|
||||
@products = product_query.order('created_at DESC').
|
||||
ransack(params[:q]).result.
|
||||
page(params[:page] || DEFAULT_PAGE).per(params[:per_page] || DEFAULT_PER_PAGE)
|
||||
|
||||
render_paged_products @products
|
||||
end
|
||||
|
||||
def overridable
|
||||
producers = OpenFoodNetwork::Permissions.new(current_api_user).
|
||||
variant_override_producers.by_name
|
||||
|
||||
@products = paged_products_for_producers producers
|
||||
|
||||
render_paged_products @products
|
||||
end
|
||||
|
||||
def soft_delete
|
||||
authorize! :delete, Spree::Product
|
||||
@product = find_product(params[:product_id])
|
||||
authorize! :delete, @product
|
||||
@product.destroy
|
||||
render json: @product, serializer: Api::Admin::ProductSerializer, status: 204
|
||||
end
|
||||
|
||||
# POST /api/products/:product_id/clone
|
||||
#
|
||||
def clone
|
||||
authorize! :create, Spree::Product
|
||||
original_product = find_product(params[:product_id])
|
||||
authorize! :update, original_product
|
||||
|
||||
@product = original_product.duplicate
|
||||
|
||||
render json: @product, serializer: Api::Admin::ProductSerializer, status: 201
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Copied and modified from SpreeApi::BaseController to allow
|
||||
# enterprise users to access inactive products
|
||||
def product_scope
|
||||
# This line modified
|
||||
if current_api_user.has_spree_role?("admin") || current_api_user.enterprises.present?
|
||||
scope = Spree::Product
|
||||
if params[:show_deleted]
|
||||
scope = scope.with_deleted
|
||||
end
|
||||
else
|
||||
scope = Spree::Product.active
|
||||
end
|
||||
|
||||
scope.includes(:master)
|
||||
end
|
||||
|
||||
def paged_products_for_producers(producers)
|
||||
Spree::Product.scoped.
|
||||
merge(product_scope).
|
||||
where(supplier_id: producers).
|
||||
by_producer.by_name.
|
||||
ransack(params[:q]).result.
|
||||
page(params[:page]).per(params[:per_page])
|
||||
end
|
||||
|
||||
def render_paged_products(products)
|
||||
serializer = ActiveModel::ArraySerializer.new(
|
||||
products,
|
||||
each_serializer: ::Api::Admin::ProductSerializer
|
||||
)
|
||||
|
||||
render text: {
|
||||
products: serializer,
|
||||
# This line is used by the PagedFetcher JS service (inventory).
|
||||
pages: products.num_pages,
|
||||
# This hash is used by the BulkProducts JS service.
|
||||
pagination: pagination_data(products)
|
||||
}.to_json
|
||||
end
|
||||
|
||||
def pagination_data(results)
|
||||
{
|
||||
results: results.total_count,
|
||||
pages: results.num_pages,
|
||||
page: (params[:page] || DEFAULT_PAGE).to_i,
|
||||
per_page: (params[:per_page] || DEFAULT_PER_PAGE).to_i
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
105
app/controllers/api/shipments_controller.rb
Normal file
105
app/controllers/api/shipments_controller.rb
Normal file
@@ -0,0 +1,105 @@
|
||||
require 'open_food_network/scope_variant_to_hub'
|
||||
|
||||
module Api
|
||||
class ShipmentsController < Api::BaseController
|
||||
respond_to :json
|
||||
|
||||
before_filter :find_order
|
||||
before_filter :find_and_update_shipment, only: [:ship, :ready, :add, :remove]
|
||||
|
||||
def create
|
||||
variant = scoped_variant(params[:variant_id])
|
||||
quantity = params[:quantity].to_i
|
||||
@shipment = get_or_create_shipment(params[:stock_location_id])
|
||||
|
||||
@order.contents.add(variant, quantity, nil, @shipment)
|
||||
|
||||
@shipment.refresh_rates
|
||||
@shipment.save!
|
||||
|
||||
render json: @shipment.reload, serializer: Api::ShipmentSerializer, status: :ok
|
||||
end
|
||||
|
||||
def update
|
||||
authorize! :read, Spree::Shipment
|
||||
@shipment = @order.shipments.find_by_number!(params[:id])
|
||||
params[:shipment] ||= []
|
||||
unlock = params[:shipment].delete(:unlock)
|
||||
|
||||
if unlock == 'yes'
|
||||
@shipment.adjustment.open
|
||||
end
|
||||
|
||||
@shipment.update_attributes(params[:shipment])
|
||||
|
||||
if unlock == 'yes'
|
||||
@shipment.adjustment.close
|
||||
end
|
||||
|
||||
render json: @shipment.reload, serializer: Api::ShipmentSerializer, status: :ok
|
||||
end
|
||||
|
||||
def ready
|
||||
authorize! :read, Spree::Shipment
|
||||
unless @shipment.ready?
|
||||
if @shipment.can_ready?
|
||||
@shipment.ready!
|
||||
else
|
||||
render(json: { error: I18n.t(:cannot_ready, scope: "spree.api.shipment") },
|
||||
status: :unprocessable_entity) && return
|
||||
end
|
||||
end
|
||||
render json: @shipment, serializer: Api::ShipmentSerializer, status: :ok
|
||||
end
|
||||
|
||||
def ship
|
||||
authorize! :read, Spree::Shipment
|
||||
unless @shipment.shipped?
|
||||
@shipment.ship!
|
||||
end
|
||||
render json: @shipment, serializer: Api::ShipmentSerializer, status: :ok
|
||||
end
|
||||
|
||||
def add
|
||||
variant = scoped_variant(params[:variant_id])
|
||||
quantity = params[:quantity].to_i
|
||||
|
||||
@order.contents.add(variant, quantity, nil, @shipment)
|
||||
|
||||
render json: @shipment, serializer: Api::ShipmentSerializer, status: :ok
|
||||
end
|
||||
|
||||
def remove
|
||||
variant = scoped_variant(params[:variant_id])
|
||||
quantity = params[:quantity].to_i
|
||||
|
||||
@order.contents.remove(variant, quantity, @shipment)
|
||||
@shipment.reload if @shipment.persisted?
|
||||
|
||||
render json: @shipment, serializer: Api::ShipmentSerializer, status: :ok
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_order
|
||||
@order = Spree::Order.find_by_number!(params[:order_id])
|
||||
authorize! :read, @order
|
||||
end
|
||||
|
||||
def find_and_update_shipment
|
||||
@shipment = @order.shipments.find_by_number!(params[:id])
|
||||
@shipment.update_attributes(params[:shipment])
|
||||
@shipment.reload
|
||||
end
|
||||
|
||||
def scoped_variant(variant_id)
|
||||
variant = Spree::Variant.find(variant_id)
|
||||
OpenFoodNetwork::ScopeVariantToHub.new(@order.distributor).scope(variant)
|
||||
variant
|
||||
end
|
||||
|
||||
def get_or_create_shipment(stock_location_id)
|
||||
@order.shipment || @order.shipments.create(stock_location_id: stock_location_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
12
app/controllers/api/taxonomies_controller.rb
Normal file
12
app/controllers/api/taxonomies_controller.rb
Normal file
@@ -0,0 +1,12 @@
|
||||
module Api
|
||||
class TaxonomiesController < Api::BaseController
|
||||
respond_to :json
|
||||
|
||||
skip_authorization_check only: :jstree
|
||||
|
||||
def jstree
|
||||
@taxonomy = Spree::Taxonomy.find(params[:id])
|
||||
render json: @taxonomy.root, serializer: Api::TaxonJstreeSerializer
|
||||
end
|
||||
end
|
||||
end
|
||||
71
app/controllers/api/taxons_controller.rb
Normal file
71
app/controllers/api/taxons_controller.rb
Normal file
@@ -0,0 +1,71 @@
|
||||
module Api
|
||||
class TaxonsController < Api::BaseController
|
||||
respond_to :json
|
||||
|
||||
skip_authorization_check only: [:index, :show, :jstree]
|
||||
|
||||
def index
|
||||
if taxonomy
|
||||
@taxons = taxonomy.root.children
|
||||
else
|
||||
if params[:ids]
|
||||
@taxons = Spree::Taxon.where(id: params[:ids].split(","))
|
||||
else
|
||||
@taxons = Spree::Taxon.ransack(params[:q]).result
|
||||
end
|
||||
end
|
||||
render json: @taxons, each_serializer: Api::TaxonSerializer
|
||||
end
|
||||
|
||||
def jstree
|
||||
@taxon = taxon
|
||||
render json: @taxon.children, each_serializer: Api::TaxonJstreeSerializer
|
||||
end
|
||||
|
||||
def create
|
||||
authorize! :create, Spree::Taxon
|
||||
@taxon = Spree::Taxon.new(params[:taxon])
|
||||
@taxon.taxonomy_id = params[:taxonomy_id]
|
||||
taxonomy = Spree::Taxonomy.find_by_id(params[:taxonomy_id])
|
||||
|
||||
if taxonomy.nil?
|
||||
@taxon.errors[:taxonomy_id] = I18n.t(:invalid_taxonomy_id, scope: 'spree.api')
|
||||
invalid_resource!(@taxon) && return
|
||||
end
|
||||
|
||||
@taxon.parent_id = taxonomy.root.id unless params[:taxon][:parent_id]
|
||||
|
||||
if @taxon.save
|
||||
render json: @taxon, serializer: Api::TaxonSerializer, status: :created
|
||||
else
|
||||
invalid_resource!(@taxon)
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
authorize! :update, Spree::Taxon
|
||||
if taxon.update_attributes(params[:taxon])
|
||||
render json: taxon, serializer: Api::TaxonSerializer, status: :ok
|
||||
else
|
||||
invalid_resource!(taxon)
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
authorize! :delete, Spree::Taxon
|
||||
taxon.destroy
|
||||
render json: taxon, serializer: Api::TaxonSerializer, status: :no_content
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def taxonomy
|
||||
return if params[:taxonomy_id].blank?
|
||||
@taxonomy ||= Spree::Taxonomy.find(params[:taxonomy_id])
|
||||
end
|
||||
|
||||
def taxon
|
||||
@taxon ||= taxonomy.taxons.find(params[:id])
|
||||
end
|
||||
end
|
||||
end
|
||||
79
app/controllers/api/variants_controller.rb
Normal file
79
app/controllers/api/variants_controller.rb
Normal file
@@ -0,0 +1,79 @@
|
||||
module Api
|
||||
class VariantsController < Api::BaseController
|
||||
respond_to :json
|
||||
|
||||
skip_authorization_check only: [:index, :show]
|
||||
before_filter :product
|
||||
|
||||
def index
|
||||
@variants = scope.includes(:option_values).ransack(params[:q]).result
|
||||
render json: @variants, each_serializer: Api::VariantSerializer
|
||||
end
|
||||
|
||||
def show
|
||||
@variant = scope.includes(:option_values).find(params[:id])
|
||||
render json: @variant, serializer: Api::VariantSerializer
|
||||
end
|
||||
|
||||
def create
|
||||
authorize! :create, Spree::Variant
|
||||
@variant = scope.new(params[:variant])
|
||||
if @variant.save
|
||||
render json: @variant, serializer: Api::VariantSerializer, status: 201
|
||||
else
|
||||
invalid_resource!(@variant)
|
||||
end
|
||||
end
|
||||
|
||||
def update
|
||||
authorize! :update, Spree::Variant
|
||||
@variant = scope.find(params[:id])
|
||||
if @variant.update_attributes(params[:variant])
|
||||
render json: @variant, serializer: Api::VariantSerializer, status: 200
|
||||
else
|
||||
invalid_resource!(@product)
|
||||
end
|
||||
end
|
||||
|
||||
def soft_delete
|
||||
@variant = scope.find(params[:variant_id])
|
||||
authorize! :delete, @variant
|
||||
|
||||
VariantDeleter.new.delete(@variant)
|
||||
render json: @variant, serializer: Api::VariantSerializer, status: 204
|
||||
end
|
||||
|
||||
def destroy
|
||||
authorize! :delete, Spree::Variant
|
||||
@variant = scope.find(params[:id])
|
||||
@variant.destroy
|
||||
render json: @variant, serializer: Api::VariantSerializer, status: 204
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def product
|
||||
@product ||= Spree::Product.find_by_permalink(params[:product_id]) if params[:product_id]
|
||||
end
|
||||
|
||||
def scope
|
||||
if @product
|
||||
unless current_api_user.has_spree_role?("admin") || params[:show_deleted]
|
||||
variants = @product.variants_including_master
|
||||
else
|
||||
variants = @product.variants_including_master.with_deleted
|
||||
end
|
||||
else
|
||||
variants = Spree::Variant.scoped
|
||||
if current_api_user.has_spree_role?("admin")
|
||||
unless params[:show_deleted]
|
||||
variants = Spree::Variant.active
|
||||
end
|
||||
else
|
||||
variants = variants.active
|
||||
end
|
||||
end
|
||||
variants
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -152,7 +152,7 @@ class CheckoutController < Spree::CheckoutController
|
||||
end
|
||||
|
||||
def update_failed
|
||||
clear_ship_address
|
||||
current_order.updater.shipping_address_from_distributor
|
||||
RestartCheckout.new(@order).call
|
||||
|
||||
respond_to do |format|
|
||||
@@ -165,15 +165,6 @@ class CheckoutController < Spree::CheckoutController
|
||||
end
|
||||
end
|
||||
|
||||
# When we have a pickup Shipping Method,
|
||||
# we clone the distributor address into ship_address before_save
|
||||
# We don't want this data in the form, so we clear it out
|
||||
def clear_ship_address
|
||||
unless current_order.shipping_method.andand.require_ship_address
|
||||
current_order.ship_address = Spree::Address.default
|
||||
end
|
||||
end
|
||||
|
||||
def load_order
|
||||
@order = current_order
|
||||
redirect_to(main_app.shop_path) && return unless @order && @order.checkout_allowed?
|
||||
|
||||
9
app/controllers/spree/admin/countries_controller.rb
Normal file
9
app/controllers/spree/admin/countries_controller.rb
Normal file
@@ -0,0 +1,9 @@
|
||||
module Spree
|
||||
module Admin
|
||||
class CountriesController < ResourceController
|
||||
def collection
|
||||
super.order(:name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
35
app/controllers/spree/admin/general_settings_controller.rb
Normal file
35
app/controllers/spree/admin/general_settings_controller.rb
Normal file
@@ -0,0 +1,35 @@
|
||||
module Spree
|
||||
module Admin
|
||||
class GeneralSettingsController < Spree::Admin::BaseController
|
||||
def edit
|
||||
@preferences_general = [:site_name, :default_seo_title, :default_meta_keywords,
|
||||
:default_meta_description, :site_url, :bugherd_api_key]
|
||||
@preferences_security = [:allow_ssl_in_production,
|
||||
:allow_ssl_in_staging, :allow_ssl_in_development_and_test,
|
||||
:check_for_spree_alerts]
|
||||
@preferences_currency = [:display_currency, :hide_cents]
|
||||
end
|
||||
|
||||
def update
|
||||
params.each do |name, value|
|
||||
next unless Spree::Config.has_preference? name
|
||||
Spree::Config[name] = value
|
||||
end
|
||||
flash[:success] = Spree.t(:successfully_updated, resource: Spree.t(:general_settings))
|
||||
|
||||
redirect_to edit_admin_general_settings_path
|
||||
end
|
||||
|
||||
def dismiss_alert
|
||||
return unless request.xhr? && params[:alert_id]
|
||||
dismissed = Spree::Config[:dismissed_spree_alerts] || ''
|
||||
Spree::Config.set(dismissed_spree_alerts: dismissed.
|
||||
split(',').
|
||||
push(params[:alert_id]).
|
||||
join(','))
|
||||
filter_dismissed_alerts
|
||||
render nothing: true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,14 +0,0 @@
|
||||
module Spree
|
||||
module Admin
|
||||
GeneralSettingsController.class_eval do
|
||||
end
|
||||
|
||||
module GeneralSettingsEditPreferences
|
||||
def edit
|
||||
super
|
||||
@preferences_general << :bugherd_api_key
|
||||
end
|
||||
end
|
||||
GeneralSettingsController.prepend(GeneralSettingsEditPreferences)
|
||||
end
|
||||
end
|
||||
79
app/controllers/spree/admin/image_settings_controller.rb
Normal file
79
app/controllers/spree/admin/image_settings_controller.rb
Normal file
@@ -0,0 +1,79 @@
|
||||
module Spree
|
||||
module Admin
|
||||
class ImageSettingsController < Spree::Admin::BaseController
|
||||
def edit
|
||||
@styles = ActiveSupport::JSON.decode(Spree::Config[:attachment_styles])
|
||||
@headers = ActiveSupport::JSON.decode(Spree::Config[:s3_headers])
|
||||
end
|
||||
|
||||
def update
|
||||
update_styles(params)
|
||||
update_headers(params) if Spree::Config[:use_s3]
|
||||
|
||||
Spree::Config.set(params[:preferences])
|
||||
update_paperclip_settings
|
||||
|
||||
respond_to do |format|
|
||||
format.html {
|
||||
flash[:success] = Spree.t(:image_settings_updated)
|
||||
redirect_to spree.edit_admin_image_settings_path
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def update_styles(params)
|
||||
if params[:new_attachment_styles].present?
|
||||
params[:new_attachment_styles].each do |_index, style|
|
||||
params[:attachment_styles][style[:name]] = style[:value] unless style[:value].empty?
|
||||
end
|
||||
end
|
||||
|
||||
styles = params[:attachment_styles]
|
||||
|
||||
Spree::Config[:attachment_styles] = ActiveSupport::JSON.encode(styles) unless styles.nil?
|
||||
end
|
||||
|
||||
def update_headers(params)
|
||||
if params[:new_s3_headers].present?
|
||||
params[:new_s3_headers].each do |_index, header|
|
||||
params[:s3_headers][header[:name]] = header[:value] unless header[:value].empty?
|
||||
end
|
||||
end
|
||||
|
||||
headers = params[:s3_headers]
|
||||
|
||||
Spree::Config[:s3_headers] = ActiveSupport::JSON.encode(headers) unless headers.nil?
|
||||
end
|
||||
|
||||
def update_paperclip_settings
|
||||
if Spree::Config[:use_s3]
|
||||
s3_creds = { access_key_id: Spree::Config[:s3_access_key],
|
||||
secret_access_key: Spree::Config[:s3_secret],
|
||||
bucket: Spree::Config[:s3_bucket] }
|
||||
Spree::Image.attachment_definitions[:attachment][:storage] = :s3
|
||||
Spree::Image.attachment_definitions[:attachment][:s3_credentials] = s3_creds
|
||||
Spree::Image.attachment_definitions[:attachment][:s3_headers] =
|
||||
ActiveSupport::JSON.decode(Spree::Config[:s3_headers])
|
||||
Spree::Image.attachment_definitions[:attachment][:bucket] = Spree::Config[:s3_bucket]
|
||||
else
|
||||
Spree::Image.attachment_definitions[:attachment].delete :storage
|
||||
end
|
||||
|
||||
Spree::Image.attachment_definitions[:attachment][:styles] =
|
||||
ActiveSupport::JSON.decode(Spree::Config[:attachment_styles]).symbolize_keys!
|
||||
Spree::Image.attachment_definitions[:attachment][:path] = Spree::Config[:attachment_path]
|
||||
Spree::Image.attachment_definitions[:attachment][:default_url] =
|
||||
Spree::Config[:attachment_default_url]
|
||||
Spree::Image.attachment_definitions[:attachment][:default_style] =
|
||||
Spree::Config[:attachment_default_style]
|
||||
|
||||
# Spree stores attachent definitions in JSON. This converts the style name and format to
|
||||
# strings. However, when paperclip encounters these, it doesn't recognise the format.
|
||||
# Here we solve that problem by converting format and style name to symbols.
|
||||
Spree::Image.reformat_styles
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,11 +0,0 @@
|
||||
Spree::Admin::ImageSettingsController.class_eval do
|
||||
# Spree stores attachent definitions in JSON. This converts the style name and format to
|
||||
# strings. However, when paperclip encounters these, it doesn't recognise the format.
|
||||
# Here we solve that problem by converting format and style name to symbols.
|
||||
def update_paperclip_settings_with_format_styles
|
||||
update_paperclip_settings_without_format_styles
|
||||
Spree::Image.reformat_styles
|
||||
end
|
||||
|
||||
alias_method_chain :update_paperclip_settings, :format_styles
|
||||
end
|
||||
39
app/controllers/spree/admin/mail_methods_controller.rb
Normal file
39
app/controllers/spree/admin/mail_methods_controller.rb
Normal file
@@ -0,0 +1,39 @@
|
||||
module Spree
|
||||
module Admin
|
||||
class MailMethodsController < Spree::Admin::BaseController
|
||||
after_filter :initialize_mail_settings
|
||||
|
||||
def update
|
||||
if params[:smtp_password].blank?
|
||||
params.delete(:smtp_password)
|
||||
end
|
||||
|
||||
params.each do |name, value|
|
||||
next unless Spree::Config.has_preference? name
|
||||
Spree::Config[name] = value
|
||||
end
|
||||
|
||||
flash[:success] = Spree.t(:successfully_updated, resource: Spree.t(:mail_methods))
|
||||
render :edit
|
||||
end
|
||||
|
||||
def testmail
|
||||
if TestMailer.test_email(try_spree_current_user).deliver
|
||||
flash[:success] = Spree.t('admin.mail_methods.testmail.delivery_success')
|
||||
else
|
||||
flash[:error] = Spree.t('admin.mail_methods.testmail.delivery_error')
|
||||
end
|
||||
rescue StandardError => e
|
||||
flash[:error] = Spree.t('admin.mail_methods.testmail.error') % { e: e }
|
||||
ensure
|
||||
redirect_to edit_admin_mail_method_url
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def initialize_mail_settings
|
||||
Spree::Core::MailSettings.init
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -3,7 +3,6 @@ require 'open_food_network/spree_api_key_loader'
|
||||
Spree::Admin::OrdersController.class_eval do
|
||||
include OpenFoodNetwork::SpreeApiKeyLoader
|
||||
helper CheckoutHelper
|
||||
before_filter :load_spree_api_key, only: :bulk_management
|
||||
before_filter :load_order, only: %i[show edit update fire resend invoice print print_ticket]
|
||||
|
||||
before_filter :load_distribution_choices, only: [:new, :edit, :update]
|
||||
@@ -27,6 +26,10 @@ Spree::Admin::OrdersController.class_eval do
|
||||
# within the page then fetches the data it needs from Api::OrdersController
|
||||
end
|
||||
|
||||
def bulk_management
|
||||
load_spree_api_key
|
||||
end
|
||||
|
||||
def edit
|
||||
@order.shipments.map &:refresh_rates
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
require 'open_food_network/spree_api_key_loader'
|
||||
require 'open_food_network/referer_parser'
|
||||
require 'open_food_network/permissions'
|
||||
|
||||
Spree::Admin::ProductsController.class_eval do
|
||||
include OpenFoodNetwork::SpreeApiKeyLoader
|
||||
@@ -29,6 +30,11 @@ Spree::Admin::ProductsController.class_eval do
|
||||
@show_latest_import = params[:latest_import] || false
|
||||
end
|
||||
|
||||
def new
|
||||
@object.shipping_category = DefaultShippingCategory.find_or_create
|
||||
super
|
||||
end
|
||||
|
||||
def create
|
||||
delete_stock_params_and_set_after do
|
||||
super
|
||||
@@ -43,24 +49,16 @@ Spree::Admin::ProductsController.class_eval do
|
||||
delete_stock_params_and_set_after do
|
||||
super
|
||||
end
|
||||
|
||||
clear_variants_unit_description if @object.variant_unit == 'items'
|
||||
end
|
||||
|
||||
def bulk_update
|
||||
collection_hash = Hash[params[:products].each_with_index.map { |p, i| [i, p] }]
|
||||
product_set = Spree::ProductSet.new(collection_attributes: collection_hash)
|
||||
|
||||
params[:filters] ||= {}
|
||||
bulk_index_query = params[:filters].reduce("") do |string, filter|
|
||||
"#{string}q[#{filter[:property][:db_column]}_#{filter[:predicate][:predicate]}]=#{filter[:value]};"
|
||||
end
|
||||
product_set = product_set_from_params(params)
|
||||
|
||||
# Ensure we're authorised to update all products
|
||||
product_set.collection.each { |p| authorize! :update, p }
|
||||
|
||||
if product_set.save
|
||||
redirect_to "/api/products/bulk_products?page=1;per_page=500;#{bulk_index_query}"
|
||||
redirect_to main_app.bulk_products_api_products_path( bulk_index_query(params) )
|
||||
else
|
||||
if product_set.errors.present?
|
||||
render json: { errors: product_set.errors }, status: :bad_request
|
||||
@@ -73,7 +71,8 @@ Spree::Admin::ProductsController.class_eval do
|
||||
protected
|
||||
|
||||
def collection
|
||||
# This method is copied directly from the spree product controller, except where we narrow the search below with the managed_by search to support
|
||||
# This method is copied directly from the spree product controller
|
||||
# except where we narrow the search below with the managed_by search to support
|
||||
# enterprise users.
|
||||
# TODO: There has to be a better way!!!
|
||||
return @collection if @collection.present?
|
||||
@@ -108,14 +107,32 @@ Spree::Admin::ProductsController.class_eval do
|
||||
|
||||
private
|
||||
|
||||
def product_set_from_params(params)
|
||||
collection_hash = Hash[params[:products].each_with_index.map { |p, i| [i, p] }]
|
||||
Spree::ProductSet.new(collection_attributes: collection_hash)
|
||||
end
|
||||
|
||||
def bulk_index_query(params)
|
||||
params[:filters].to_h.merge(page: params[:page], per_page: params[:per_page])
|
||||
end
|
||||
|
||||
def load_form_data
|
||||
@producers = OpenFoodNetwork::Permissions.new(spree_current_user).managed_product_enterprises.is_primary_producer.by_name
|
||||
@producers = OpenFoodNetwork::Permissions.new(spree_current_user).
|
||||
managed_product_enterprises.is_primary_producer.by_name
|
||||
@taxons = Spree::Taxon.order(:name)
|
||||
@import_dates = product_import_dates.uniq.to_json
|
||||
end
|
||||
|
||||
def product_import_dates
|
||||
import_dates = Spree::Variant.
|
||||
options = [{ id: '0', name: '' }]
|
||||
product_import_dates_query.collect(&:import_date).
|
||||
map { |i| options.push(id: i.to_date, name: i.to_date.to_formatted_s(:long)) }
|
||||
|
||||
options
|
||||
end
|
||||
|
||||
def product_import_dates_query
|
||||
Spree::Variant.
|
||||
select('DISTINCT spree_variants.import_date').
|
||||
joins(:product).
|
||||
where('spree_products.supplier_id IN (?)', editable_enterprises.collect(&:id)).
|
||||
@@ -123,18 +140,14 @@ Spree::Admin::ProductsController.class_eval do
|
||||
where(spree_variants: { is_master: false }).
|
||||
where(spree_variants: { deleted_at: nil }).
|
||||
order('spree_variants.import_date DESC')
|
||||
|
||||
options = [{ id: '0', name: '' }]
|
||||
import_dates.collect(&:import_date).map { |i| options.push(id: i.to_date, name: i.to_date.to_formatted_s(:long)) }
|
||||
|
||||
options
|
||||
end
|
||||
|
||||
def strip_new_properties
|
||||
unless spree_current_user.admin? || params[:product][:product_properties_attributes].nil?
|
||||
names = Spree::Property.pluck(:name)
|
||||
params[:product][:product_properties_attributes].each do |key, property|
|
||||
params[:product][:product_properties_attributes].delete key unless names.include? property[:property_name]
|
||||
return if spree_current_user.admin? || params[:product][:product_properties_attributes].nil?
|
||||
names = Spree::Property.pluck(:name)
|
||||
params[:product][:product_properties_attributes].each do |key, property|
|
||||
unless names.include? property[:property_name]
|
||||
params[:product][:product_properties_attributes].delete key
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -149,21 +162,35 @@ Spree::Admin::ProductsController.class_eval do
|
||||
end
|
||||
|
||||
def set_stock_levels(product, on_hand, on_demand)
|
||||
variant = product.master
|
||||
if product.variants.any?
|
||||
variant = product.variants.first
|
||||
variant = product_variant(product)
|
||||
|
||||
begin
|
||||
variant.on_demand = on_demand if on_demand.present?
|
||||
variant.on_hand = on_hand.to_i if on_hand.present?
|
||||
rescue StandardError => error
|
||||
notify_bugsnag(error, product, variant)
|
||||
raise error
|
||||
end
|
||||
end
|
||||
|
||||
def notify_bugsnag(error, product, variant)
|
||||
Bugsnag.notify(error) do |report|
|
||||
report.add_tab(:product, product.attributes)
|
||||
report.add_tab(:product_error, product.errors.first) unless product.valid?
|
||||
report.add_tab(:variant, variant.attributes)
|
||||
report.add_tab(:variant_error, variant.errors.first) unless variant.valid?
|
||||
end
|
||||
end
|
||||
|
||||
def product_variant(product)
|
||||
if product.variants.any?
|
||||
product.variants.first
|
||||
else
|
||||
product.master
|
||||
end
|
||||
variant.on_demand = on_demand if on_demand.present?
|
||||
variant.on_hand = on_hand.to_i if on_hand.present?
|
||||
end
|
||||
|
||||
def set_product_master_variant_price_to_zero
|
||||
@product.price = 0 if @product.price.nil?
|
||||
end
|
||||
|
||||
def clear_variants_unit_description
|
||||
@object.variants.each do |variant|
|
||||
variant.update_attribute :unit_description, ''
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -126,7 +126,8 @@ Spree::Admin::ReportsController.class_eval do
|
||||
@include_blank = I18n.t(:all)
|
||||
|
||||
# -- Build Report with Order Grouper
|
||||
@report = OpenFoodNetwork::OrdersAndFulfillmentsReport.new spree_current_user, params, render_content?
|
||||
@report = OpenFoodNetwork::OrdersAndFulfillmentsReport.new(permissions,
|
||||
params, render_content?)
|
||||
@table = order_grouper_table
|
||||
csv_file_name = "#{params[:report_type]}_#{timestamp}.csv"
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
module Spree
|
||||
module Admin
|
||||
class ShippingCategoriesController < ResourceController
|
||||
end
|
||||
end
|
||||
end
|
||||
84
app/controllers/spree/admin/shipping_methods_controller.rb
Normal file
84
app/controllers/spree/admin/shipping_methods_controller.rb
Normal file
@@ -0,0 +1,84 @@
|
||||
module Spree
|
||||
module Admin
|
||||
class ShippingMethodsController < ResourceController
|
||||
before_filter :load_data, except: [:index]
|
||||
before_filter :set_shipping_category, only: [:create, :update]
|
||||
before_filter :set_zones, only: [:create, :update]
|
||||
before_filter :load_hubs, only: [:new, :edit, :create, :update]
|
||||
|
||||
# Sort shipping methods by distributor name
|
||||
def collection
|
||||
collection = super
|
||||
collection = collection.managed_by(spree_current_user).by_name
|
||||
|
||||
if params.key? :enterprise_id
|
||||
distributor = Enterprise.find params[:enterprise_id]
|
||||
collection = collection.for_distributor(distributor)
|
||||
end
|
||||
|
||||
collection
|
||||
end
|
||||
|
||||
def new
|
||||
@object.shipping_categories = [DefaultShippingCategory.find_or_create]
|
||||
super
|
||||
end
|
||||
|
||||
def destroy
|
||||
# Our reports are not adapted to soft deleted shipping_methods so here we prevent
|
||||
# the deletion (even soft) of shipping_methods that are referenced in orders
|
||||
if order = order_referenced_by_shipping_method
|
||||
flash[:error] = I18n.t(:shipping_method_destroy_error, number: order.number)
|
||||
redirect_to(collection_url) && return
|
||||
end
|
||||
|
||||
@object.touch :deleted_at
|
||||
flash[:success] = flash_message_for(@object, :successfully_removed)
|
||||
|
||||
respond_with(@object) do |format|
|
||||
format.html { redirect_to collection_url }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def order_referenced_by_shipping_method
|
||||
Order.joins(shipments: :shipping_rates)
|
||||
.where( spree_shipping_rates: { shipping_method_id: @object } )
|
||||
.first
|
||||
end
|
||||
|
||||
def load_hubs
|
||||
# rubocop:disable Style/TernaryParentheses
|
||||
@hubs = Enterprise.managed_by(spree_current_user).is_distributor.sort_by! do |d|
|
||||
[(@shipping_method.has_distributor? d) ? 0 : 1, d.name]
|
||||
end
|
||||
# rubocop:enable Style/TernaryParentheses
|
||||
end
|
||||
|
||||
def set_shipping_category
|
||||
return true if params["shipping_method"][:shipping_categories] == ""
|
||||
@shipping_method.shipping_categories =
|
||||
Spree::ShippingCategory.where(id: params["shipping_method"][:shipping_categories])
|
||||
@shipping_method.save
|
||||
params[:shipping_method].delete(:shipping_categories)
|
||||
end
|
||||
|
||||
def set_zones
|
||||
return true if params["shipping_method"][:zones] == ""
|
||||
@shipping_method.zones = Spree::Zone.where(id: params["shipping_method"][:zones])
|
||||
@shipping_method.save
|
||||
params[:shipping_method].delete(:zones)
|
||||
end
|
||||
|
||||
def location_after_save
|
||||
edit_admin_shipping_method_path(@shipping_method)
|
||||
end
|
||||
|
||||
def load_data
|
||||
@available_zones = Zone.order(:name)
|
||||
@calculators = ShippingMethod.calculators.sort_by(&:name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,42 +0,0 @@
|
||||
module Spree
|
||||
module Admin
|
||||
ShippingMethodsController.class_eval do
|
||||
before_filter :do_not_destroy_referenced_shipping_methods, only: :destroy
|
||||
before_filter :load_hubs, only: [:new, :edit, :create, :update]
|
||||
|
||||
# Sort shipping methods by distributor name
|
||||
def collection
|
||||
collection = super
|
||||
collection = collection.managed_by(spree_current_user).by_name
|
||||
|
||||
if params.key? :enterprise_id
|
||||
distributor = Enterprise.find params[:enterprise_id]
|
||||
collection = collection.for_distributor(distributor)
|
||||
end
|
||||
|
||||
collection
|
||||
end
|
||||
|
||||
# Spree allows soft deletes of shipping_methods but our reports are not adapted to that
|
||||
# Here we prevent the deletion (even soft) of shipping_methods that are referenced in orders
|
||||
def do_not_destroy_referenced_shipping_methods
|
||||
order = Order.joins(shipments: :shipping_rates)
|
||||
.where( spree_shipping_rates: { shipping_method_id: @object } )
|
||||
.first
|
||||
return unless order
|
||||
flash[:error] = I18n.t(:shipping_method_destroy_error, number: order.number)
|
||||
redirect_to(collection_url) && return
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_hubs
|
||||
# rubocop:disable Style/TernaryParentheses
|
||||
@hubs = Enterprise.managed_by(spree_current_user).is_distributor.sort_by! do |d|
|
||||
[(@shipping_method.has_distributor? d) ? 0 : 1, d.name]
|
||||
end
|
||||
# rubocop:enable Style/TernaryParentheses
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
29
app/controllers/spree/admin/states_controller.rb
Normal file
29
app/controllers/spree/admin/states_controller.rb
Normal file
@@ -0,0 +1,29 @@
|
||||
module Spree
|
||||
module Admin
|
||||
class StatesController < ResourceController
|
||||
belongs_to 'spree/country'
|
||||
before_filter :load_data
|
||||
|
||||
def index
|
||||
respond_with(@collection) do |format|
|
||||
format.html
|
||||
format.js { render partial: 'state_list' }
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def location_after_save
|
||||
admin_country_states_url(@country)
|
||||
end
|
||||
|
||||
def collection
|
||||
super.order(:name)
|
||||
end
|
||||
|
||||
def load_data
|
||||
@countries = Country.order(:name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
19
app/controllers/spree/admin/tax_categories_controller.rb
Normal file
19
app/controllers/spree/admin/tax_categories_controller.rb
Normal file
@@ -0,0 +1,19 @@
|
||||
module Spree
|
||||
module Admin
|
||||
class TaxCategoriesController < ResourceController
|
||||
def destroy
|
||||
if @object.destroy
|
||||
flash[:success] = flash_message_for(@object, :successfully_removed)
|
||||
respond_with(@object) do |format|
|
||||
format.html { redirect_to collection_url }
|
||||
format.js { render partial: "spree/admin/shared/destroy" }
|
||||
end
|
||||
else
|
||||
respond_with(@object) do |format|
|
||||
format.html { redirect_to collection_url }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
26
app/controllers/spree/admin/tax_rates_controller.rb
Normal file
26
app/controllers/spree/admin/tax_rates_controller.rb
Normal file
@@ -0,0 +1,26 @@
|
||||
module Spree
|
||||
module Admin
|
||||
class TaxRatesController < ResourceController
|
||||
before_filter :load_data
|
||||
|
||||
update.after :update_after
|
||||
create.after :create_after
|
||||
|
||||
private
|
||||
|
||||
def load_data
|
||||
@available_zones = Zone.order(:name)
|
||||
@available_categories = TaxCategory.order(:name)
|
||||
@calculators = TaxRate.calculators.sort_by(&:name)
|
||||
end
|
||||
|
||||
def update_after
|
||||
Rails.cache.delete('vat_rates')
|
||||
end
|
||||
|
||||
def create_after
|
||||
Rails.cache.delete('vat_rates')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
15
app/controllers/spree/admin/tax_settings_controller.rb
Normal file
15
app/controllers/spree/admin/tax_settings_controller.rb
Normal file
@@ -0,0 +1,15 @@
|
||||
module Spree
|
||||
module Admin
|
||||
class TaxSettingsController < Spree::Admin::BaseController
|
||||
def update
|
||||
Spree::Config.set(params[:preferences])
|
||||
|
||||
respond_to do |format|
|
||||
format.html {
|
||||
redirect_to edit_admin_tax_settings_path
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
21
app/controllers/spree/admin/taxonomies_controller.rb
Normal file
21
app/controllers/spree/admin/taxonomies_controller.rb
Normal file
@@ -0,0 +1,21 @@
|
||||
module Spree
|
||||
module Admin
|
||||
class TaxonomiesController < ResourceController
|
||||
respond_to :json, :only => [:get_children]
|
||||
|
||||
def get_children
|
||||
@taxons = Taxon.find(params[:parent_id]).children
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def location_after_save
|
||||
if @taxonomy.created_at == @taxonomy.updated_at
|
||||
edit_admin_taxonomy_url(@taxonomy)
|
||||
else
|
||||
admin_taxonomies_url
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
118
app/controllers/spree/admin/taxons_controller.rb
Normal file
118
app/controllers/spree/admin/taxons_controller.rb
Normal file
@@ -0,0 +1,118 @@
|
||||
module Spree
|
||||
module Admin
|
||||
class TaxonsController < Spree::Admin::BaseController
|
||||
respond_to :html, :json, :js
|
||||
|
||||
def search
|
||||
if params[:ids]
|
||||
@taxons = Spree::Taxon.where(id: params[:ids].split(','))
|
||||
else
|
||||
@taxons = Spree::Taxon.limit(20).search(name_cont: params[:q]).result
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
@taxonomy = Taxonomy.find(params[:taxonomy_id])
|
||||
@taxon = @taxonomy.taxons.build(params[:taxon])
|
||||
if @taxon.save
|
||||
respond_with(@taxon) do |format|
|
||||
format.json { render json: @taxon.to_json }
|
||||
end
|
||||
else
|
||||
flash[:error] = Spree.t('errors.messages.could_not_create_taxon')
|
||||
respond_with(@taxon) do |format|
|
||||
format.html do
|
||||
if redirect_to @taxonomy
|
||||
edit_admin_taxonomy_url(@taxonomy)
|
||||
else
|
||||
admin_taxonomies_url
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
@taxonomy = Taxonomy.find(params[:taxonomy_id])
|
||||
@taxon = @taxonomy.taxons.find(params[:id])
|
||||
@permalink_part = @taxon.permalink.split("/").last
|
||||
end
|
||||
|
||||
def update
|
||||
@taxonomy = Taxonomy.find(params[:taxonomy_id])
|
||||
@taxon = @taxonomy.taxons.find(params[:id])
|
||||
parent_id = params[:taxon][:parent_id]
|
||||
new_position = params[:taxon][:position]
|
||||
|
||||
if parent_id || new_position # taxon is being moved
|
||||
new_parent = parent_id.nil? ? @taxon.parent : Taxon.find(parent_id.to_i)
|
||||
new_position = new_position.nil? ? -1 : new_position.to_i
|
||||
|
||||
# Bellow is a very complicated way of finding where in nested set we
|
||||
# should actually move the taxon to achieve sane results,
|
||||
# JS is giving us the desired position, which was awesome for previous setup,
|
||||
# but now it's quite complicated to find where we should put it as we have
|
||||
# to differenciate between moving to the same branch, up down and into
|
||||
# first position.
|
||||
new_siblings = new_parent.children
|
||||
if new_position <= 0 && new_siblings.empty?
|
||||
@taxon.move_to_child_of(new_parent)
|
||||
elsif new_parent.id != @taxon.parent_id
|
||||
if new_position.zero?
|
||||
@taxon.move_to_left_of(new_siblings.first)
|
||||
else
|
||||
@taxon.move_to_right_of(new_siblings[new_position - 1])
|
||||
end
|
||||
elsif new_position < new_siblings.index(@taxon)
|
||||
@taxon.move_to_left_of(new_siblings[new_position]) # we move up
|
||||
else
|
||||
@taxon.move_to_right_of(new_siblings[new_position - 1]) # we move down
|
||||
end
|
||||
# Reset legacy position, if any extensions still rely on it
|
||||
new_parent.children.reload.each{ |t| t.update_column(:position, t.position) }
|
||||
|
||||
if parent_id
|
||||
@taxon.reload
|
||||
@taxon.set_permalink
|
||||
@taxon.save!
|
||||
@update_children = true
|
||||
end
|
||||
end
|
||||
|
||||
if params.key? "permalink_part"
|
||||
parent_permalink = @taxon.permalink.split("/")[0...-1].join("/")
|
||||
parent_permalink += "/" if parent_permalink.present?
|
||||
params[:taxon][:permalink] = parent_permalink + params[:permalink_part]
|
||||
end
|
||||
# check if we need to rename child taxons if parent name or permalink changes
|
||||
if params[:taxon][:name] != @taxon.name || params[:taxon][:permalink] != @taxon.permalink
|
||||
@update_children = true
|
||||
end
|
||||
|
||||
if @taxon.update_attributes(params[:taxon])
|
||||
flash[:success] = flash_message_for(@taxon, :successfully_updated)
|
||||
end
|
||||
|
||||
# rename child taxons
|
||||
if @update_children
|
||||
@taxon.descendants.each do |taxon|
|
||||
taxon.reload
|
||||
taxon.set_permalink
|
||||
taxon.save!
|
||||
end
|
||||
end
|
||||
|
||||
respond_with(@taxon) do |format|
|
||||
format.html { redirect_to edit_admin_taxonomy_url(@taxonomy) }
|
||||
format.json { render json: @taxon.to_json }
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
@taxon = Taxon.find(params[:id])
|
||||
@taxon.destroy
|
||||
respond_with(@taxon) { |format| format.json { render json: '' } }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -46,7 +46,12 @@ module Spree
|
||||
@user.spree_roles = roles.reject(&:blank?).collect{ |r| Spree::Role.find(r) }
|
||||
end
|
||||
|
||||
flash.now[:success] = Spree.t(:account_updated)
|
||||
message = if new_email_unconfirmed?
|
||||
Spree.t(:email_updated)
|
||||
else
|
||||
Spree.t(:account_updated)
|
||||
end
|
||||
flash.now[:success] = message
|
||||
end
|
||||
render :edit
|
||||
end
|
||||
@@ -126,6 +131,10 @@ module Spree
|
||||
def load_roles
|
||||
@roles = Spree::Role.scoped
|
||||
end
|
||||
|
||||
def new_email_unconfirmed?
|
||||
params[:user][:email] != @user.email
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
26
app/controllers/spree/admin/zones_controller.rb
Normal file
26
app/controllers/spree/admin/zones_controller.rb
Normal file
@@ -0,0 +1,26 @@
|
||||
module Spree
|
||||
module Admin
|
||||
class ZonesController < ResourceController
|
||||
before_filter :load_data, except: [:index]
|
||||
|
||||
def new
|
||||
@zone.zone_members.build
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def collection
|
||||
params[:q] ||= {}
|
||||
params[:q][:s] ||= "ascend_by_name"
|
||||
@search = super.ransack(params[:q])
|
||||
@zones = @search.result.page(params[:page]).per(Spree::Config[:orders_per_page])
|
||||
end
|
||||
|
||||
def load_data
|
||||
@countries = Country.order(:name)
|
||||
@states = State.order(:name)
|
||||
@zones = Zone.order(:name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
130
app/controllers/spree/api/base_controller.rb
Normal file
130
app/controllers/spree/api/base_controller.rb
Normal file
@@ -0,0 +1,130 @@
|
||||
require_dependency 'spree/api/controller_setup'
|
||||
|
||||
module Spree
|
||||
module Api
|
||||
class BaseController < ActionController::Metal
|
||||
include Spree::Api::ControllerSetup
|
||||
include Spree::Core::ControllerHelpers::SSL
|
||||
include ::ActionController::Head
|
||||
|
||||
self.responder = Spree::Api::Responders::AppResponder
|
||||
|
||||
respond_to :json
|
||||
|
||||
attr_accessor :current_api_user
|
||||
|
||||
before_filter :set_content_type
|
||||
before_filter :check_for_user_or_api_key, :if => :requires_authentication?
|
||||
before_filter :authenticate_user
|
||||
after_filter :set_jsonp_format
|
||||
|
||||
rescue_from Exception, :with => :error_during_processing
|
||||
rescue_from CanCan::AccessDenied, :with => :unauthorized
|
||||
rescue_from ActiveRecord::RecordNotFound, :with => :not_found
|
||||
|
||||
helper Spree::Api::ApiHelpers
|
||||
|
||||
ssl_allowed
|
||||
|
||||
def set_jsonp_format
|
||||
if params[:callback] && request.get?
|
||||
self.response_body = "#{params[:callback]}(#{response_body})"
|
||||
headers["Content-Type"] = 'application/javascript'
|
||||
end
|
||||
end
|
||||
|
||||
def map_nested_attributes_keys(klass, attributes)
|
||||
nested_keys = klass.nested_attributes_options.keys
|
||||
attributes.inject({}) do |h, (k, v)|
|
||||
key = nested_keys.include?(k.to_sym) ? "#{k}_attributes" : k
|
||||
h[key] = v
|
||||
h
|
||||
end.with_indifferent_access
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_content_type
|
||||
content_type = case params[:format]
|
||||
when "json"
|
||||
"application/json"
|
||||
when "xml"
|
||||
"text/xml"
|
||||
end
|
||||
headers["Content-Type"] = content_type
|
||||
end
|
||||
|
||||
def check_for_user_or_api_key
|
||||
# User is already authenticated with Spree, make request this way instead.
|
||||
return true if @current_api_user = try_spree_current_user ||
|
||||
!requires_authentication?
|
||||
|
||||
return if api_key.present?
|
||||
render("spree/api/errors/must_specify_api_key", status: :unauthorized) && return
|
||||
end
|
||||
|
||||
def authenticate_user
|
||||
return if @current_api_user
|
||||
|
||||
if requires_authentication? || api_key.present?
|
||||
unless @current_api_user = Spree.user_class.find_by_spree_api_key(api_key.to_s)
|
||||
render("spree/api/errors/invalid_api_key", status: :unauthorized) && return
|
||||
end
|
||||
else
|
||||
# An anonymous user
|
||||
@current_api_user = Spree.user_class.new
|
||||
end
|
||||
end
|
||||
|
||||
def unauthorized
|
||||
render("spree/api/errors/unauthorized", status: :unauthorized) && return
|
||||
end
|
||||
|
||||
def error_during_processing(exception)
|
||||
render(text: { exception: exception.message }.to_json,
|
||||
status: :unprocessable_entity) && return
|
||||
end
|
||||
|
||||
def requires_authentication?
|
||||
true
|
||||
end
|
||||
|
||||
def not_found
|
||||
render("spree/api/errors/not_found", status: :not_found) && return
|
||||
end
|
||||
|
||||
def current_ability
|
||||
Spree::Ability.new(current_api_user)
|
||||
end
|
||||
|
||||
def invalid_resource!(resource)
|
||||
@resource = resource
|
||||
render "spree/api/errors/invalid_resource", status: :unprocessable_entity
|
||||
end
|
||||
|
||||
def api_key
|
||||
request.headers["X-Spree-Token"] || params[:token]
|
||||
end
|
||||
helper_method :api_key
|
||||
|
||||
def find_product(id)
|
||||
product_scope.find_by_permalink!(id.to_s)
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
product_scope.find(id)
|
||||
end
|
||||
|
||||
def product_scope
|
||||
if current_api_user.has_spree_role?("admin")
|
||||
scope = Product
|
||||
if params[:show_deleted]
|
||||
scope = scope.with_deleted
|
||||
end
|
||||
else
|
||||
scope = Product.active
|
||||
end
|
||||
|
||||
scope.includes(:master)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,13 +0,0 @@
|
||||
Spree::Api::LineItemsController.class_eval do
|
||||
around_filter :apply_enterprise_fees_with_lock, only: :update
|
||||
|
||||
private
|
||||
|
||||
def apply_enterprise_fees_with_lock
|
||||
authorize! :read, order
|
||||
order.with_lock do
|
||||
yield
|
||||
order.update_distribution_charge!
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,86 +0,0 @@
|
||||
require 'open_food_network/permissions'
|
||||
|
||||
Spree::Api::ProductsController.class_eval do
|
||||
def managed
|
||||
authorize! :admin, Spree::Product
|
||||
authorize! :read, Spree::Product
|
||||
|
||||
@products = product_scope.ransack(params[:q]).result.managed_by(current_api_user).page(params[:page]).per(params[:per_page])
|
||||
respond_with(@products, default_template: :index)
|
||||
end
|
||||
|
||||
# TODO: This should be named 'managed'. Is the action above used? Maybe we should remove it.
|
||||
def bulk_products
|
||||
@products = OpenFoodNetwork::Permissions.new(current_api_user).editable_products.
|
||||
merge(product_scope).
|
||||
order('created_at DESC').
|
||||
ransack(params[:q]).result.
|
||||
page(params[:page]).per(params[:per_page])
|
||||
|
||||
render_paged_products @products
|
||||
end
|
||||
|
||||
def overridable
|
||||
producers = OpenFoodNetwork::Permissions.new(current_api_user).
|
||||
variant_override_producers.by_name
|
||||
|
||||
@products = paged_products_for_producers producers
|
||||
|
||||
render_paged_products @products
|
||||
end
|
||||
|
||||
def soft_delete
|
||||
authorize! :delete, Spree::Product
|
||||
@product = find_product(params[:product_id])
|
||||
authorize! :delete, @product
|
||||
@product.destroy
|
||||
respond_with(@product, status: 204)
|
||||
end
|
||||
|
||||
# POST /api/products/:product_id/clone
|
||||
#
|
||||
def clone
|
||||
authorize! :create, Spree::Product
|
||||
original_product = find_product(params[:product_id])
|
||||
authorize! :update, original_product
|
||||
|
||||
@product = original_product.duplicate
|
||||
|
||||
respond_with(@product, status: 201, default_template: :show)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Copied and modified from Spree::Api::BaseController to allow
|
||||
# enterprise users to access inactive products
|
||||
def product_scope
|
||||
if current_api_user.has_spree_role?("admin") || current_api_user.enterprises.present? # This line modified
|
||||
scope = Spree::Product
|
||||
if params[:show_deleted]
|
||||
scope = scope.with_deleted
|
||||
end
|
||||
else
|
||||
scope = Spree::Product.active
|
||||
end
|
||||
|
||||
scope.includes(:master)
|
||||
end
|
||||
|
||||
def paged_products_for_producers(producers)
|
||||
Spree::Product.scoped.
|
||||
merge(product_scope).
|
||||
where(supplier_id: producers).
|
||||
by_producer.by_name.
|
||||
ransack(params[:q]).result.
|
||||
page(params[:page]).per(params[:per_page])
|
||||
end
|
||||
|
||||
def render_paged_products(products)
|
||||
serializer = ActiveModel::ArraySerializer.new(
|
||||
products,
|
||||
each_serializer: Api::Admin::ProductSerializer
|
||||
)
|
||||
|
||||
render text: { products: serializer, pages: products.num_pages }.to_json
|
||||
end
|
||||
end
|
||||
@@ -1,47 +0,0 @@
|
||||
require 'open_food_network/scope_variant_to_hub'
|
||||
|
||||
Spree::Api::ShipmentsController.class_eval do
|
||||
def create
|
||||
variant = scoped_variant(params[:variant_id])
|
||||
quantity = params[:quantity].to_i
|
||||
@shipment = get_or_create_shipment(params[:stock_location_id])
|
||||
|
||||
@order.contents.add(variant, quantity, nil, @shipment)
|
||||
|
||||
@shipment.refresh_rates
|
||||
@shipment.save!
|
||||
|
||||
respond_with(@shipment.reload, default_template: :show)
|
||||
end
|
||||
|
||||
def add
|
||||
variant = scoped_variant(params[:variant_id])
|
||||
quantity = params[:quantity].to_i
|
||||
|
||||
@order.contents.add(variant, quantity, nil, @shipment)
|
||||
|
||||
respond_with(@shipment, default_template: :show)
|
||||
end
|
||||
|
||||
def remove
|
||||
variant = scoped_variant(params[:variant_id])
|
||||
quantity = params[:quantity].to_i
|
||||
|
||||
@order.contents.remove(variant, quantity, @shipment)
|
||||
@shipment.reload if @shipment.persisted?
|
||||
|
||||
respond_with(@shipment, default_template: :show)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def scoped_variant(variant_id)
|
||||
variant = Spree::Variant.find(variant_id)
|
||||
OpenFoodNetwork::ScopeVariantToHub.new(@order.distributor).scope(variant)
|
||||
variant
|
||||
end
|
||||
|
||||
def get_or_create_shipment(stock_location_id)
|
||||
@order.shipment || @order.shipments.create(stock_location_id: stock_location_id)
|
||||
end
|
||||
end
|
||||
@@ -1,9 +0,0 @@
|
||||
Spree::Api::VariantsController.class_eval do
|
||||
def soft_delete
|
||||
@variant = scope.find(params[:variant_id])
|
||||
authorize! :delete, @variant
|
||||
|
||||
VariantDeleter.new.delete(@variant)
|
||||
respond_with @variant, status: 204
|
||||
end
|
||||
end
|
||||
@@ -29,7 +29,7 @@ module Spree
|
||||
|
||||
def load_order
|
||||
@order = current_order
|
||||
redirect_to main_app.cart_path && return unless @order
|
||||
redirect_to(main_app.cart_path) && return unless @order
|
||||
|
||||
if params[:state]
|
||||
redirect_to checkout_state_path(@order.state) if @order.can_go_to_state?(params[:state])
|
||||
|
||||
@@ -38,10 +38,6 @@ module Spree
|
||||
end
|
||||
end
|
||||
|
||||
def nav_bar
|
||||
render partial: 'spree/shared/nav_bar'
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def accurate_title
|
||||
|
||||
13
app/helpers/spree/admin/general_settings_helper.rb
Normal file
13
app/helpers/spree/admin/general_settings_helper.rb
Normal file
@@ -0,0 +1,13 @@
|
||||
module Spree
|
||||
module Admin
|
||||
module GeneralSettingsHelper
|
||||
def currency_options
|
||||
currencies = ::Money::Currency.table.map do |_code, details|
|
||||
iso = details[:iso_code]
|
||||
[iso, "#{details[:name]} (#{iso})"]
|
||||
end
|
||||
options_from_collection_for_select(currencies, :first, :last, Spree::Config[:currency])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -18,6 +18,7 @@ module Spree
|
||||
klass = Spree::Order if klass == :bulk_order_management
|
||||
klass = EnterpriseGroup if klass == :group
|
||||
klass = VariantOverride if klass == :Inventory
|
||||
klass = ProductImport::ProductImporter if klass == :import
|
||||
klass = Spree::Admin::ReportsController if klass == :report
|
||||
klass
|
||||
end
|
||||
|
||||
9
app/helpers/spree/admin/taxons_helper.rb
Normal file
9
app/helpers/spree/admin/taxons_helper.rb
Normal file
@@ -0,0 +1,9 @@
|
||||
module Spree
|
||||
module Admin
|
||||
module TaxonsHelper
|
||||
def taxon_path(taxon)
|
||||
taxon.ancestors.reverse.collect(&:name).join( " >> ")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
120
app/helpers/spree/api/api_helpers.rb
Normal file
120
app/helpers/spree/api/api_helpers.rb
Normal file
@@ -0,0 +1,120 @@
|
||||
module Spree
|
||||
module Api
|
||||
module ApiHelpers
|
||||
def required_fields_for(model)
|
||||
required_fields = model._validators.select do |_field, validations|
|
||||
validations.any? { |v| v.is_a?(ActiveModel::Validations::PresenceValidator) }
|
||||
end.map(&:first) # get fields that are invalid
|
||||
# Permalinks presence is validated, but are really automatically generated
|
||||
# Therefore we shouldn't tell API clients that they MUST send one through
|
||||
required_fields.map!(&:to_s).delete("permalink")
|
||||
required_fields
|
||||
end
|
||||
|
||||
def product_attributes
|
||||
[:id, :name, :description, :price, :available_on, :permalink, :meta_description,
|
||||
:meta_keywords, :shipping_category_id, :taxon_ids]
|
||||
end
|
||||
|
||||
def product_property_attributes
|
||||
[:id, :product_id, :property_id, :value, :property_name]
|
||||
end
|
||||
|
||||
def variant_attributes
|
||||
[:id, :name, :sku, :price, :weight, :height, :width, :depth,
|
||||
:is_master, :cost_price, :permalink]
|
||||
end
|
||||
|
||||
def image_attributes
|
||||
[:id, :position, :attachment_content_type, :attachment_file_name,
|
||||
:type, :attachment_updated_at, :attachment_width, :attachment_height, :alt]
|
||||
end
|
||||
|
||||
def option_value_attributes
|
||||
[:id, :name, :presentation, :option_type_name, :option_type_id]
|
||||
end
|
||||
|
||||
def order_attributes
|
||||
[:id, :number, :item_total, :total, :state, :adjustment_total, :user_id,
|
||||
:created_at, :updated_at, :completed_at, :payment_total,
|
||||
:shipment_state, :payment_state, :email, :special_instructions, :token]
|
||||
end
|
||||
|
||||
def line_item_attributes
|
||||
[:id, :quantity, :price, :variant_id]
|
||||
end
|
||||
|
||||
def option_type_attributes
|
||||
[:id, :name, :presentation, :position]
|
||||
end
|
||||
|
||||
def payment_attributes
|
||||
[:id, :source_type, :source_id, :amount, :payment_method_id,
|
||||
:response_code, :state, :avs_response, :created_at, :updated_at]
|
||||
end
|
||||
|
||||
def payment_method_attributes
|
||||
[:id, :name, :description]
|
||||
end
|
||||
|
||||
def shipment_attributes
|
||||
[:id, :tracking, :number, :cost, :shipped_at, :state]
|
||||
end
|
||||
|
||||
def taxonomy_attributes
|
||||
[:id, :name]
|
||||
end
|
||||
|
||||
def taxon_attributes
|
||||
[:id, :name, :pretty_name, :permalink, :position, :parent_id, :taxonomy_id]
|
||||
end
|
||||
|
||||
def inventory_unit_attributes
|
||||
[:id, :lock_version, :state, :variant_id, :shipment_id, :return_authorization_id]
|
||||
end
|
||||
|
||||
def return_authorization_attributes
|
||||
[:id, :number, :state, :amount, :order_id, :reason, :created_at, :updated_at]
|
||||
end
|
||||
|
||||
def country_attributes
|
||||
[:id, :iso_name, :iso, :iso3, :name, :numcode]
|
||||
end
|
||||
|
||||
def state_attributes
|
||||
[:id, :name, :abbr, :country_id]
|
||||
end
|
||||
|
||||
def adjustment_attributes
|
||||
[:id, :source_type, :source_id, :adjustable_type, :adjustable_id, :originator_type,
|
||||
:originator_id, :amount, :label, :mandatory, :locked, :eligible, :created_at, :updated_at]
|
||||
end
|
||||
|
||||
def creditcard_attributes
|
||||
[:id, :month, :year, :cc_type, :last_digits, :first_name, :last_name,
|
||||
:gateway_customer_profile_id, :gateway_payment_profile_id]
|
||||
end
|
||||
|
||||
def user_attributes
|
||||
[:id, :email, :created_at, :updated_at]
|
||||
end
|
||||
|
||||
def property_attributes
|
||||
[:id, :name, :presentation]
|
||||
end
|
||||
|
||||
def stock_location_attributes
|
||||
[:id, :name, :address1, :address2, :city,
|
||||
:state_id, :state_name, :country_id, :zipcode, :phone, :active]
|
||||
end
|
||||
|
||||
def stock_movement_attributes
|
||||
[:id, :quantity, :stock_item_id]
|
||||
end
|
||||
|
||||
def stock_item_attributes
|
||||
[:id, :count_on_hand, :backorderable, :lock_version, :stock_location_id, :variant_id]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -59,7 +59,7 @@ class SubscriptionPlacementJob
|
||||
end
|
||||
|
||||
def move_to_completion(order)
|
||||
until order.completed? do order.next! end
|
||||
AdvanceOrderService.new(order).call!
|
||||
end
|
||||
|
||||
def unavailable_stock_lines_for(order)
|
||||
|
||||
@@ -13,8 +13,43 @@ module Calculator
|
||||
|
||||
def compute(object)
|
||||
line_items = line_items_for object
|
||||
total_weight = line_items.sum { |li| ((li.variant.andand.weight || 0) * li.quantity) }
|
||||
total_weight * preferred_per_kg
|
||||
(total_weight(line_items) * preferred_per_kg).round(2)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def total_weight(line_items)
|
||||
line_items.sum do |line_item|
|
||||
line_item_weight(line_item)
|
||||
end
|
||||
end
|
||||
|
||||
def line_item_weight(line_item)
|
||||
if line_item.final_weight_volume.present?
|
||||
weight_per_final_weight_volume(line_item)
|
||||
else
|
||||
weight_per_variant(line_item) * line_item.quantity
|
||||
end
|
||||
end
|
||||
|
||||
def weight_per_variant(line_item)
|
||||
line_item.variant.andand.weight || 0
|
||||
end
|
||||
|
||||
def weight_per_final_weight_volume(line_item)
|
||||
if line_item.variant.product.andand.variant_unit == 'weight'
|
||||
# Divided by 1000 because grams is the base weight unit and the calculator price is per_kg
|
||||
line_item.final_weight_volume / 1000.0
|
||||
else
|
||||
weight_per_variant(line_item) * quantity_implied_in_final_weight_volume(line_item)
|
||||
end
|
||||
end
|
||||
|
||||
# Example: 2 (line_item.quantity) wine glasses of 125mL (line_item.variant.unit_value)
|
||||
# Customer ends up getting 350mL (line_item.final_weight_volume) of wine
|
||||
# that represent 2.8 (quantity_implied_in_final_weight_volume) glasses of wine
|
||||
def quantity_implied_in_final_weight_volume(line_item)
|
||||
(1.0 * line_item.final_weight_volume / line_item.variant.unit_value).round(3)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -19,7 +19,7 @@ module OrderShipment
|
||||
#
|
||||
# @return [ShippingMethod]
|
||||
def shipping_method
|
||||
return if shipments.empty?
|
||||
return if shipments.blank?
|
||||
shipments.first.shipping_method
|
||||
end
|
||||
|
||||
|
||||
@@ -25,36 +25,21 @@ module VariantStock
|
||||
#
|
||||
# @return [Float|Integer]
|
||||
def on_hand
|
||||
warn_deprecation(__method__, '#total_on_hand')
|
||||
|
||||
total_on_hand
|
||||
end
|
||||
|
||||
# Sets the stock level of the variant.
|
||||
# This will only work if `track_inventory_levels` config is set
|
||||
# and if there is a stock item for the variant.
|
||||
# This will only work if there is a stock item for the variant.
|
||||
#
|
||||
# @raise [StandardError] when the track_inventory_levels config key is not set
|
||||
# and when the variant has no stock item
|
||||
# @raise [StandardError] when the variant has no stock item
|
||||
def on_hand=(new_level)
|
||||
warn_deprecation(__method__, '#total_on_hand')
|
||||
|
||||
error = 'Cannot set on_hand value when Spree::Config[:track_inventory_levels] is false'
|
||||
raise error unless Spree::Config.track_inventory_levels
|
||||
|
||||
raise_error_if_no_stock_item_available
|
||||
|
||||
overwrite_stock_levels(new_level)
|
||||
end
|
||||
|
||||
# Checks whether this variant is produced on demand.
|
||||
#
|
||||
# In Spree 2.0 this attribute is removed in favour of
|
||||
# track_inventory_levels only. It was initially introduced in
|
||||
# https://github.com/openfoodfoundation/spree/commit/20b5ad9835dca7f41a40ad16c7b45f987eea6dcc
|
||||
def on_demand
|
||||
warn_deprecation(__method__, 'StockItem#backorderable?')
|
||||
|
||||
# A variant that has not been saved yet, doesn't have a stock item
|
||||
# This provides a default value for variant.on_demand using Spree::StockLocation.backorderable_default
|
||||
return Spree::StockLocation.first.backorderable_default if stock_items.empty?
|
||||
@@ -69,8 +54,6 @@ module VariantStock
|
||||
#
|
||||
# @raise [StandardError] when the variant has no stock item yet
|
||||
def on_demand=(new_value)
|
||||
warn_deprecation(__method__, 'StockItem#backorderable=')
|
||||
|
||||
raise_error_if_no_stock_item_available
|
||||
|
||||
# There should be only one at the default stock location.
|
||||
@@ -89,8 +72,6 @@ module VariantStock
|
||||
# Here we depend only on variant.total_on_hand and variant.on_demand.
|
||||
# This way, variant_overrides only need to override variant.total_on_hand and variant.on_demand.
|
||||
def can_supply?(quantity)
|
||||
return true unless Spree::Config[:track_inventory_levels]
|
||||
|
||||
on_demand || total_on_hand >= quantity
|
||||
end
|
||||
|
||||
@@ -100,13 +81,13 @@ module VariantStock
|
||||
# Here we depend only on variant.total_on_hand and variant.on_demand.
|
||||
# This way, variant_overrides only need to override variant.total_on_hand and variant.on_demand.
|
||||
def fill_status(quantity)
|
||||
if on_hand >= quantity
|
||||
on_hand = quantity
|
||||
backordered = 0
|
||||
else
|
||||
on_hand = [0, total_on_hand].max
|
||||
backordered = on_demand ? (quantity - on_hand) : 0
|
||||
end
|
||||
on_hand = if total_on_hand >= quantity || on_demand
|
||||
quantity
|
||||
else
|
||||
[0, total_on_hand].max
|
||||
end
|
||||
|
||||
backordered = 0
|
||||
|
||||
[on_hand, backordered]
|
||||
end
|
||||
@@ -117,6 +98,9 @@ module VariantStock
|
||||
def move(quantity, originator = nil)
|
||||
raise_error_if_no_stock_item_available
|
||||
|
||||
# Don't change variant stock if variant is on_demand
|
||||
return if on_demand
|
||||
|
||||
# Creates a stock movement: it updates stock_item.count_on_hand and fills backorders
|
||||
#
|
||||
# This is the original Spree::StockLocation#move,
|
||||
@@ -155,11 +139,4 @@ module VariantStock
|
||||
def stock_item
|
||||
stock_items.first
|
||||
end
|
||||
|
||||
def warn_deprecation(method_name, new_method_name)
|
||||
ActiveSupport::Deprecation.warn(
|
||||
"`##{method_name}` is deprecated and will be removed. " \
|
||||
"Please use `#{new_method_name}` instead."
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -90,7 +90,6 @@ class Enterprise < ActiveRecord::Base
|
||||
validates :permalink, uniqueness: true, presence: true
|
||||
validate :shopfront_taxons
|
||||
validate :enforce_ownership_limit, if: lambda { owner_id_changed? && !owner_id.nil? }
|
||||
validates :description, length: { maximum: 255 }
|
||||
|
||||
before_validation :initialize_permalink, if: lambda { permalink.nil? }
|
||||
before_validation :ensure_owner_is_manager, if: lambda { owner_id_changed? && !owner_id.nil? }
|
||||
@@ -464,9 +463,11 @@ class Enterprise < ActiveRecord::Base
|
||||
self.permalink = Enterprise.find_available_permalink(name)
|
||||
end
|
||||
|
||||
# Touch distributors without them touching their distributors.
|
||||
# We avoid an infinite loop and don't need to touch the whole distributor tree.
|
||||
def touch_distributors
|
||||
Enterprise.distributing_products(supplied_products.select(:id)).
|
||||
where('enterprises.id != ?', id).
|
||||
find_each(&:touch)
|
||||
update_all(updated_at: Time.zone.now)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
# Tells whether a particular feature is enabled or not
|
||||
class FeatureFlags
|
||||
# Constructor
|
||||
#
|
||||
# @param user [User]
|
||||
def initialize(user)
|
||||
@user = user
|
||||
end
|
||||
|
||||
# Checks whether product import is enabled for the specified user
|
||||
#
|
||||
# @return [Boolean]
|
||||
def product_import_enabled?
|
||||
user.superadmin?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :user
|
||||
end
|
||||
@@ -207,12 +207,15 @@ class AbilityDecorator
|
||||
end
|
||||
|
||||
def add_order_management_abilities(user)
|
||||
# Enterprise User can only access orders that they are a distributor for
|
||||
can [:index, :create], Spree::Order
|
||||
can [:read, :update, :fire, :resend, :invoice, :print, :print_ticket], Spree::Order do |order|
|
||||
# We allow editing orders with a nil distributor as this state occurs
|
||||
# during the order creation process from the admin backend
|
||||
order.distributor.nil? || user.enterprises.include?(order.distributor) || order.order_cycle.andand.coordinated_by?(user)
|
||||
order.distributor.nil? ||
|
||||
# Enterprise User can access orders that they are a distributor for
|
||||
user.enterprises.include?(order.distributor) ||
|
||||
# Enterprise User can access orders that are placed inside a OC they coordinate
|
||||
order.order_cycle.andand.coordinated_by?(user)
|
||||
end
|
||||
can [:admin, :bulk_management, :managed], Spree::Order do
|
||||
user.admin? || user.enterprises.any?(&:is_distributor)
|
||||
|
||||
@@ -1,9 +1,22 @@
|
||||
module Spree
|
||||
Price.class_eval do
|
||||
acts_as_paranoid without_default_scope: true
|
||||
|
||||
after_save :refresh_products_cache
|
||||
|
||||
# Allow prices to access associated soft-deleted variants.
|
||||
def variant
|
||||
Spree::Variant.unscoped { super }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def check_price
|
||||
if currency.nil?
|
||||
self.currency = Spree::Config[:currency]
|
||||
end
|
||||
end
|
||||
|
||||
def refresh_products_cache
|
||||
variant.andand.refresh_products_cache
|
||||
end
|
||||
|
||||
@@ -56,6 +56,12 @@ Spree::Product.class_eval do
|
||||
ON (o_order_cycles.id = o_exchanges.order_cycle_id)")
|
||||
}
|
||||
|
||||
scope :imported_on, lambda { |import_date|
|
||||
import_date = Time.zone.parse import_date if import_date.is_a? String
|
||||
import_date = import_date.to_date
|
||||
joins(:variants).merge(Spree::Variant.where(import_date: import_date.beginning_of_day..import_date.end_of_day))
|
||||
}
|
||||
|
||||
scope :with_order_cycles_inner, -> {
|
||||
joins(variants_including_master: { exchanges: :order_cycle })
|
||||
}
|
||||
|
||||
@@ -17,9 +17,7 @@ class Spree::ProductSet < ModelSet
|
||||
# variant.update_attributes( { price: xx.x } )
|
||||
#
|
||||
def update_attributes(attributes)
|
||||
if attributes[:taxon_ids].present?
|
||||
attributes[:taxon_ids] = attributes[:taxon_ids].split(',')
|
||||
end
|
||||
split_taxon_ids!(attributes)
|
||||
|
||||
found_model = @collection.find do |model|
|
||||
model.id.to_s == attributes[:id].to_s && model.persisted?
|
||||
@@ -28,12 +26,20 @@ class Spree::ProductSet < ModelSet
|
||||
if found_model.nil?
|
||||
@klass.new(attributes).save unless @reject_if.andand.call(attributes)
|
||||
else
|
||||
update_product_only_attributes(found_model, attributes) &&
|
||||
update_product_variants(found_model, attributes) &&
|
||||
update_product_master(found_model, attributes)
|
||||
update_product(found_model, attributes)
|
||||
end
|
||||
end
|
||||
|
||||
def split_taxon_ids!(attributes)
|
||||
attributes[:taxon_ids] = attributes[:taxon_ids].split(',') if attributes[:taxon_ids].present?
|
||||
end
|
||||
|
||||
def update_product(found_model, attributes)
|
||||
update_product_only_attributes(found_model, attributes) &&
|
||||
update_product_variants(found_model, attributes) &&
|
||||
update_product_master(found_model, attributes)
|
||||
end
|
||||
|
||||
def update_product_only_attributes(product, attributes)
|
||||
variant_related_attrs = [:id, :variants_attributes, :master_attributes]
|
||||
product_related_attrs = attributes.except(*variant_related_attrs)
|
||||
@@ -90,8 +96,23 @@ class Spree::ProductSet < ModelSet
|
||||
|
||||
variant = product.variants.create(variant_attributes)
|
||||
|
||||
variant.on_demand = on_demand if on_demand.present?
|
||||
variant.on_hand = on_hand.to_i if on_hand.present?
|
||||
begin
|
||||
variant.on_demand = on_demand if on_demand.present?
|
||||
variant.on_hand = on_hand.to_i if on_hand.present?
|
||||
rescue StandardError => error
|
||||
notify_bugsnag(error, product, variant, variant_attributes)
|
||||
raise error
|
||||
end
|
||||
end
|
||||
|
||||
def notify_bugsnag(error, product, variant, variant_attributes)
|
||||
Bugsnag.notify(error) do |report|
|
||||
report.add_tab(:product, product.attributes)
|
||||
report.add_tab(:product_error, product.errors.first) unless product.valid?
|
||||
report.add_tab(:variant_attributes, variant_attributes)
|
||||
report.add_tab(:variant, variant.attributes)
|
||||
report.add_tab(:variant_error, variant.errors.first) unless variant.valid?
|
||||
end
|
||||
end
|
||||
|
||||
def collection_attributes=(attributes)
|
||||
|
||||
@@ -32,7 +32,7 @@ module Spree
|
||||
# NOTE: This is an override of spree's method, needed to allow orders
|
||||
# without line items (ie. user invoices) to not have inventory units
|
||||
def require_inventory
|
||||
return false unless Spree::Config[:track_inventory_levels] && line_items.count > 0 # This line altered
|
||||
return false unless line_items.count > 0 # This line altered
|
||||
order.completed? && !order.canceled?
|
||||
end
|
||||
end
|
||||
|
||||
10
app/models/spree/stock_movement_decorator.rb
Normal file
10
app/models/spree/stock_movement_decorator.rb
Normal file
@@ -0,0 +1,10 @@
|
||||
Spree::StockMovement.class_eval do
|
||||
after_save :refresh_products_cache
|
||||
|
||||
private
|
||||
|
||||
def refresh_products_cache
|
||||
return if stock_item.variant.blank?
|
||||
OpenFoodNetwork::ProductsCache.variant_changed stock_item.variant
|
||||
end
|
||||
end
|
||||
@@ -136,6 +136,16 @@ module Spree
|
||||
has_spree_role?('admin')
|
||||
end
|
||||
|
||||
def generate_spree_api_key!
|
||||
self.spree_api_key = SecureRandom.hex(24)
|
||||
save!
|
||||
end
|
||||
|
||||
def clear_spree_api_key!
|
||||
self.spree_api_key = nil
|
||||
save!
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def password_required?
|
||||
|
||||
@@ -91,6 +91,11 @@ Spree::Variant.class_eval do
|
||||
can_supply?(quantity)
|
||||
end
|
||||
|
||||
# Allow variant to access associated soft-deleted prices.
|
||||
def default_price
|
||||
Spree::Price.unscoped { super }
|
||||
end
|
||||
|
||||
def price_with_fees(distributor, order_cycle)
|
||||
price + fees_for(distributor, order_cycle)
|
||||
end
|
||||
|
||||
@@ -10,6 +10,11 @@ class SubscriptionLineItem < ActiveRecord::Base
|
||||
(price_estimate || 0) * (quantity || 0)
|
||||
end
|
||||
|
||||
# Ensure SubscriptionLineItem always has access to soft-deleted Variant attribute
|
||||
def variant
|
||||
Spree::Variant.unscoped { super }
|
||||
end
|
||||
|
||||
# Used to calculators to estimate fees
|
||||
alias_method :amount, :total_estimate
|
||||
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
Deface::Override.new(virtual_path: "spree/layouts/admin",
|
||||
name: "user_admin_tabs",
|
||||
insert_bottom: "[data-hook='admin_tabs'], #admin_tabs[data-hook]",
|
||||
partial: "spree/admin/users_tab",
|
||||
disabled: false,
|
||||
original: '031652cf5a054796022506622082ab6d2693699f')
|
||||
@@ -1,5 +0,0 @@
|
||||
Deface::Override.new(virtual_path: "spree/layouts/admin",
|
||||
name: "auth_admin_login_navigation_bar",
|
||||
insert_top: "[data-hook='admin_login_navigation_bar'], #admin_login_navigation_bar[data-hook]",
|
||||
partial: "spree/layouts/admin/login_nav",
|
||||
original: '841227d0aedf7909d62237d8778df99100087715')
|
||||
@@ -1,6 +0,0 @@
|
||||
Deface::Override.new(virtual_path: "spree/shared/_nav_bar",
|
||||
name: "auth_shared_login_bar",
|
||||
insert_before: "li#search-bar",
|
||||
partial: "spree/shared/login_bar",
|
||||
disabled: false,
|
||||
original: 'eb3fa668cd98b6a1c75c36420ef1b238a1fc55ac')
|
||||
@@ -1,3 +0,0 @@
|
||||
Deface::Override.new(virtual_path: "spree/shared/_nav_bar",
|
||||
remove: "#search-bar",
|
||||
name: "search_removal")
|
||||
@@ -1,3 +0,0 @@
|
||||
Deface::Override.new(virtual_path: "spree/shared/_sidebar",
|
||||
remove: "#sidebar",
|
||||
name: "sidebar_removal")
|
||||
@@ -1,5 +0,0 @@
|
||||
Deface::Override.new(virtual_path: "spree/layouts/admin",
|
||||
insert_bottom: "[data-hook='admin_inside_head']",
|
||||
partial: "layouts/auth_token_script",
|
||||
name: "set_auth_token_in_backend",
|
||||
original: '6bc2c5de1c8f7542d033548557437c9fe4b3ba02')
|
||||
@@ -1,5 +0,0 @@
|
||||
Deface::Override.new(virtual_path: "spree/layouts/spree_application",
|
||||
insert_bottom: "[data-hook='inside_head']",
|
||||
partial: "layouts/auth_token_script",
|
||||
name: "set_auth_token_in_frontend",
|
||||
original: '5659ac7dbf6ac6469907b005b85285b894677815')
|
||||
@@ -1,6 +0,0 @@
|
||||
/ replace_contents "td.property_name"
|
||||
|
||||
- if spree_current_user.admin?
|
||||
= f.text_field :property_name, :class => 'autocomplete'
|
||||
- else
|
||||
= f.select :property_name, @properties, { :include_blank => true }, { class: 'select2 fullwidth' }
|
||||
@@ -1,26 +0,0 @@
|
||||
/ insert_after 'table.index.sortable'
|
||||
|
||||
=f.check_box :inherits_properties
|
||||
=f.label :inherits_properties, t(".inherits_properties_checkbox_hint", supplier: @product.supplier.name)
|
||||
%br
|
||||
%br
|
||||
|
||||
#inherited_properties
|
||||
%table.index
|
||||
%thead
|
||||
%tr{"data-hook" => "producer_properties_header"}
|
||||
%th= t('admin.products.properties.inherited_property')
|
||||
%th= t('admin.description')
|
||||
%th.actions
|
||||
%tbody#producer_properties{"data-hook" => ""}
|
||||
- @product.supplier.producer_properties.each do |producer_property|
|
||||
%tr
|
||||
%td= producer_property.property.presentation
|
||||
%td= producer_property.value
|
||||
%td.actions
|
||||
|
||||
:coffee
|
||||
$(document).ready ->
|
||||
$("#inherited_properties").toggle $("input#product_inherits_properties").is(':checked')
|
||||
$("input#product_inherits_properties").change ->
|
||||
$("#inherited_properties").toggle $(this).is(':checked')
|
||||
@@ -1,5 +0,0 @@
|
||||
/ replace "tr[data-hook='product_properties_header']"
|
||||
%tr{"data-hook" => "product_properties_header"}
|
||||
%th= t('admin.products.properties.property_name')
|
||||
%th= t('admin.description')
|
||||
%th.actions
|
||||
@@ -1,2 +0,0 @@
|
||||
add_to_attributes '[data-hook="admin_variant_form_fields"]'
|
||||
attributes 'ng-app' => 'admin.products'
|
||||
@@ -1,25 +0,0 @@
|
||||
/ insert_top "[data-hook='admin_variant_form_fields']"
|
||||
|
||||
.field
|
||||
= f.label :display_name, t(:display_name)
|
||||
= f.text_field :display_name, class: "fullwidth"
|
||||
.field
|
||||
= f.label :display_as, t(:display_as)
|
||||
= f.text_field :display_as, class: "fullwidth"
|
||||
|
||||
- if product_has_variant_unit_option_type?(@product)
|
||||
- if @product.variant_unit != 'items'
|
||||
.field{"data-hook" => "unit_value", 'ng-controller' => 'variantUnitsCtrl'}
|
||||
= f.label :unit_value, "#{t('admin.'+@product.variant_unit)} ({{unitName(#{@product.variant_unit_scale}, '#{@product.variant_unit}')}})"
|
||||
= hidden_field_tag 'product_variant_unit_scale', @product.variant_unit_scale
|
||||
= text_field_tag :unit_value_human, nil, {class: "fullwidth", 'ng-model' => 'unit_value_human', 'ng-change' => 'updateValue()'}
|
||||
= f.text_field :unit_value, {hidden: true, 'ng-value' => 'unit_value'}
|
||||
|
||||
.field{"data-hook" => "unit_description"}
|
||||
= f.label :unit_description, t(:spree_admin_unit_description)
|
||||
= f.text_field :unit_description, class: "fullwidth", placeholder: t('admin.products.unit_name_placeholder')
|
||||
|
||||
:javascript
|
||||
angular.element(document.getElementById("new_variant")).ready(function() {
|
||||
angular.bootstrap(document.getElementById("new_variant"), ['admin.products']);
|
||||
});
|
||||
@@ -1,11 +0,0 @@
|
||||
/ insert_bottom "[data-hook='admin_variant_form_fields']"
|
||||
|
||||
- if Spree::Config[:track_inventory_levels]
|
||||
.field.checkbox
|
||||
%label
|
||||
= f.check_box :on_demand
|
||||
= t(:on_demand)
|
||||
.field
|
||||
= f.label :on_hand, t(:on_hand)
|
||||
.fullwidth
|
||||
= f.text_field :on_hand
|
||||
@@ -1,10 +0,0 @@
|
||||
/ replace "[data-hook='presentation']"
|
||||
|
||||
- unless variant_unit_option_type?(option_type)
|
||||
.field{"data-hook" => "presentation"}
|
||||
= label :new_variant, option_type.presentation
|
||||
- if @variant.new_record?
|
||||
= select(:new_variant, option_type.presentation, option_type.option_values.collect {|ov| [ ov.presentation, ov.id ] }, {}, {:class => 'select2 fullwidth'})
|
||||
- else
|
||||
- if opt = @variant.option_values.detect {|o| o.option_type == option_type }.try(:presentation)
|
||||
= text_field(:new_variant, option_type.presentation, :value => opt, :disabled => 'disabled', :class => 'fullwidth')
|
||||
@@ -1,33 +0,0 @@
|
||||
/ insert_bottom "[data-hook='admin_variant_form_fields']"
|
||||
:javascript
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
var on_demand = $('input#variant_on_demand');
|
||||
var on_hand = $('input#variant_on_hand');
|
||||
|
||||
disableOnHandIfOnDemand = function() {
|
||||
on_demand_checked = on_demand.attr('checked')
|
||||
if ( on_demand_checked == undefined )
|
||||
on_demand_checked = false;
|
||||
|
||||
on_hand.attr('disabled', on_demand_checked);
|
||||
if(on_demand_checked) {
|
||||
on_hand.attr('data-stock', on_hand.val());
|
||||
on_hand.val(t('admin.products.variants.infinity'));
|
||||
}
|
||||
}
|
||||
|
||||
disableOnHandIfOnDemand();
|
||||
|
||||
on_demand.change(function(){
|
||||
disableOnHandIfOnDemand();
|
||||
if(!this.checked) {
|
||||
if(on_hand.attr('data-stock') !== undefined) {
|
||||
on_hand.val(on_hand.attr('data-stock'));
|
||||
} else {
|
||||
on_hand.val("0");
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1,3 +0,0 @@
|
||||
/ insert_bottom "[data-hook='on_demand']"
|
||||
%div{'ofn-with-tip' => t('admin.products.variants.to_order_tip')}
|
||||
%a= t('admin.whats_this')
|
||||
@@ -1,14 +0,0 @@
|
||||
/ replace "[data-hook='admin_variant_form_additional_fields']"
|
||||
|
||||
.right.six.columns.omega.label-block{"data-hook" => "admin_variant_form_additional_fields"}
|
||||
- if @product.variant_unit != 'weight'
|
||||
.field{"data-hook" => 'weight'}
|
||||
= f.label 'weight', t('weight')+' (kg)'
|
||||
- value = number_with_precision(@variant.weight, :precision => 2)
|
||||
= f.text_field 'weight', :value => value, :class => 'fullwidth'
|
||||
|
||||
- [:height, :width, :depth].each do |field|
|
||||
.field{"data-hook" => field}
|
||||
= f.label field, t(field)
|
||||
- value = number_with_precision(@variant.send(field), :precision => 2)
|
||||
= f.text_field field, :value => value, :class => 'fullwidth'
|
||||
@@ -1,3 +0,0 @@
|
||||
/ replace "code[erb-loud]:contains('variant.options_text')"
|
||||
|
||||
= variant.full_name
|
||||
@@ -1,5 +0,0 @@
|
||||
<!-- surround_contents 'body' -->
|
||||
|
||||
<div <%= yield(:app_wrapper_attrs).strip.html_safe %>>
|
||||
<%= render_original %>
|
||||
</div>
|
||||
@@ -1,19 +0,0 @@
|
||||
/ replace "footer"
|
||||
|
||||
-#= render partial: "shared/footer"
|
||||
%footer
|
||||
%hr/
|
||||
|
||||
-#.row
|
||||
-#.seven.columns.offset-by-three
|
||||
-#%center
|
||||
-#%h1 What is open food network?
|
||||
-#%p
|
||||
-#%i
|
||||
-#Open food network is an online space in which people can connect with, trade and sell food directly with
|
||||
-#Australian farmers. We aim to reconnect people with their food.
|
||||
-#%hr/
|
||||
|
||||
-#.row
|
||||
-#.five.columns.secondary.offset-by-seven.secondary
|
||||
-#All rights reserved. © 2013 Open Food Foundation
|
||||
@@ -1,8 +0,0 @@
|
||||
/ replace "#logo"
|
||||
|
||||
%figure#logo.columns.eight
|
||||
- if 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
|
||||
@@ -1,2 +0,0 @@
|
||||
/ set_attributes '#top-nav-bar'
|
||||
/ attributes({:class => "columns eight"})
|
||||
@@ -1,5 +0,0 @@
|
||||
/ insert_before "#password-credentials"
|
||||
|
||||
- if @unconfirmed_email
|
||||
%p.alert-box
|
||||
= t('spree.users.show.unconfirmed_email', unconfirmed_email: @unconfirmed_email)
|
||||
@@ -4,7 +4,11 @@ class Api::AddressSerializer < ActiveModel::Serializer
|
||||
|
||||
attributes :id, :zipcode, :city, :state_name, :state_id,
|
||||
:phone, :firstname, :lastname, :address1, :address2, :city, :country_id,
|
||||
:zipcode
|
||||
:zipcode, :country_name
|
||||
|
||||
def country_name
|
||||
object.country.andand.name
|
||||
end
|
||||
|
||||
def state_name
|
||||
object.state.andand.abbr
|
||||
|
||||
8
app/serializers/api/adjustment_serializer.rb
Normal file
8
app/serializers/api/adjustment_serializer.rb
Normal file
@@ -0,0 +1,8 @@
|
||||
module Api
|
||||
class AdjustmentSerializer < ActiveModel::Serializer
|
||||
attributes :id, :amount, :label, :eligible,
|
||||
:source_type, :source_id,
|
||||
:adjustable_type, :adjustable_id,
|
||||
:originator_type, :originator_id
|
||||
end
|
||||
end
|
||||
@@ -1,4 +1,4 @@
|
||||
class Api::Admin::BasicEnterpriseSerializer < ActiveModel::Serializer
|
||||
attributes :name, :id, :is_primary_producer, :is_distributor, :sells, :category, :payment_method_ids, :shipping_method_ids
|
||||
attributes :producer_profile_only, :permalink
|
||||
attributes :name, :id, :is_primary_producer, :is_distributor, :sells, :category,
|
||||
:payment_method_ids, :shipping_method_ids, :producer_profile_only, :permalink
|
||||
end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
class Api::Admin::CustomerSerializer < ActiveModel::Serializer
|
||||
attributes :id, :email, :enterprise_id, :user_id, :code, :tags, :tag_list, :name
|
||||
attributes :allow_charges, :default_card_present?
|
||||
attributes :id, :email, :enterprise_id, :user_id, :code, :tags, :tag_list, :name,
|
||||
:allow_charges, :default_card_present?
|
||||
|
||||
has_one :ship_address, serializer: Api::AddressSerializer
|
||||
has_one :bill_address, serializer: Api::AddressSerializer
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user