mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-01-15 19:06:50 +00:00
Compare commits
673 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e23d714e83 | ||
|
|
ec01e55707 | ||
|
|
c18b996a1b | ||
|
|
98ea82462d | ||
|
|
586a9afaae | ||
|
|
f116ee156f | ||
|
|
7a9f341363 | ||
|
|
ada0fa50fc | ||
|
|
451c57da40 | ||
|
|
82a752de46 | ||
|
|
e2f3feccf0 | ||
|
|
e6bdbccffa | ||
|
|
ea9b0eca48 | ||
|
|
e8bc87e62b | ||
|
|
d7a3c50bd5 | ||
|
|
f5a0862655 | ||
|
|
595bc5d1a5 | ||
|
|
bc621a3c43 | ||
|
|
7ebf5db1f2 | ||
|
|
e806f38142 | ||
|
|
d980809a19 | ||
|
|
e6f6232607 | ||
|
|
cce30d5762 | ||
|
|
47a6ffbf66 | ||
|
|
7e5eae1b8d | ||
|
|
8c4d0f11d7 | ||
|
|
d96c1fc165 | ||
|
|
6f879cd5d9 | ||
|
|
1d75e5a671 | ||
|
|
bdd58dccf0 | ||
|
|
aaf5bcbb12 | ||
|
|
976bbd8725 | ||
|
|
341604be8a | ||
|
|
5ce320f8a2 | ||
|
|
6598c80f6e | ||
|
|
d4b84e55c2 | ||
|
|
6f5080923f | ||
|
|
afda5cc04e | ||
|
|
12e225e7c0 | ||
|
|
c19c22cb17 | ||
|
|
b5a8df00dd | ||
|
|
0aacb91f50 | ||
|
|
1b39d57800 | ||
|
|
5eb3dc4beb | ||
|
|
9849f76c1c | ||
|
|
ae2eba89ca | ||
|
|
dadbb7445b | ||
|
|
4fd307832e | ||
|
|
09ca9ac2dd | ||
|
|
b98afc00ba | ||
|
|
7332e21013 | ||
|
|
5cb0a1c371 | ||
|
|
10d6a29503 | ||
|
|
e06af77420 | ||
|
|
392d0de6c5 | ||
|
|
0fdd7dabd4 | ||
|
|
c999627d28 | ||
|
|
f2eee77a15 | ||
|
|
040c292a76 | ||
|
|
12e3b88b71 | ||
|
|
2bfa923fe1 | ||
|
|
d30362b78c | ||
|
|
28491ee948 | ||
|
|
fe4145d9d5 | ||
|
|
3ef29fde2c | ||
|
|
05e6c3daa6 | ||
|
|
9d8456cbf3 | ||
|
|
1d8f332cc6 | ||
|
|
6f554814ce | ||
|
|
f1545a4ab6 | ||
|
|
31750a7bba | ||
|
|
ad391c73ab | ||
|
|
014283447d | ||
|
|
3b2d4ae2d4 | ||
|
|
14a03aab35 | ||
|
|
904a364bf1 | ||
|
|
30df1d4345 | ||
|
|
b85e38010f | ||
|
|
7a411b0452 | ||
|
|
ecbd1fe93d | ||
|
|
14caac0212 | ||
|
|
6e9efe79b7 | ||
|
|
cff1d7224d | ||
|
|
86a500bcdf | ||
|
|
7bd0de99ac | ||
|
|
9506ea456e | ||
|
|
e173f823c8 | ||
|
|
4a818c07bb | ||
|
|
1ac9417a20 | ||
|
|
ae1c8344d1 | ||
|
|
add9c83812 | ||
|
|
993f02a989 | ||
|
|
d7d40a4a0f | ||
|
|
6bf4ed1ac5 | ||
|
|
6bdbdc06e7 | ||
|
|
2e94654f91 | ||
|
|
2a731b2db5 | ||
|
|
dcfa5fa42d | ||
|
|
ad62b258ac | ||
|
|
95f70409ee | ||
|
|
3ac57269ed | ||
|
|
8951c79f71 | ||
|
|
b3e7badd37 | ||
|
|
cec5fddf6a | ||
|
|
c4a81bdc48 | ||
|
|
9887819c16 | ||
|
|
c1b7e9f79e | ||
|
|
3fa5ca7eae | ||
|
|
65fea6291e | ||
|
|
64c2bdda1c | ||
|
|
de8df4b3e9 | ||
|
|
70bb64d58d | ||
|
|
a529525a63 | ||
|
|
50c1224139 | ||
|
|
927ab3a23a | ||
|
|
183621f90b | ||
|
|
a7dcaf15fa | ||
|
|
237854c781 | ||
|
|
3c5b01ece0 | ||
|
|
d52f9fd43f | ||
|
|
5c046b76f0 | ||
|
|
ab1ed16435 | ||
|
|
23d36e3898 | ||
|
|
c79641c77c | ||
|
|
aa4bd7f397 | ||
|
|
be07996656 | ||
|
|
e12207f3de | ||
|
|
09b800672d | ||
|
|
c59b172348 | ||
|
|
7017c8540c | ||
|
|
ae4420d9ba | ||
|
|
eb53df8238 | ||
|
|
71370e0bce | ||
|
|
ba66c0e862 | ||
|
|
c605742671 | ||
|
|
720628e49e | ||
|
|
501fa4c901 | ||
|
|
532f998b24 | ||
|
|
b7876ebfbf | ||
|
|
04e48989c9 | ||
|
|
094c3e70f7 | ||
|
|
b3eaa30f3d | ||
|
|
672f96b85b | ||
|
|
902802594f | ||
|
|
a9b5fd69d8 | ||
|
|
b258c032cc | ||
|
|
fe7b86ff60 | ||
|
|
17950ba498 | ||
|
|
ccbe33001f | ||
|
|
c5f3249172 | ||
|
|
e7eb02dfe3 | ||
|
|
17a0b18e50 | ||
|
|
2012c23956 | ||
|
|
88a5d4be47 | ||
|
|
224249d66b | ||
|
|
ceab1fe16a | ||
|
|
c1f0a0b514 | ||
|
|
ce09a8dad6 | ||
|
|
99db6f8e14 | ||
|
|
d6924d2866 | ||
|
|
3e68973812 | ||
|
|
bbc3cad67d | ||
|
|
50d3522b2c | ||
|
|
2c5bfab29f | ||
|
|
844cd79270 | ||
|
|
8ae4307a69 | ||
|
|
2c40252edb | ||
|
|
0c302b022a | ||
|
|
7581779a0d | ||
|
|
f9727de206 | ||
|
|
76daa183d5 | ||
|
|
981b874263 | ||
|
|
4362ef2cea | ||
|
|
7ca60e1990 | ||
|
|
1bf2f7ad03 | ||
|
|
8ba1a909ca | ||
|
|
c86207212f | ||
|
|
86cddb1cc4 | ||
|
|
b49c44f7ce | ||
|
|
818af47613 | ||
|
|
ef6c9ec0f0 | ||
|
|
13d01df4d8 | ||
|
|
cf30b7c883 | ||
|
|
0c0e12e165 | ||
|
|
f9af8edf27 | ||
|
|
8bf460c93a | ||
|
|
f902b8cef0 | ||
|
|
84ad996ef8 | ||
|
|
fb28940952 | ||
|
|
03f1980b1b | ||
|
|
26a325e6e0 | ||
|
|
2576d10e49 | ||
|
|
67e05cea9c | ||
|
|
0ccb0ce0e4 | ||
|
|
8c96a19e3e | ||
|
|
6e83c6dc86 | ||
|
|
d6a9d63de5 | ||
|
|
6ea343f26e | ||
|
|
43c2aca208 | ||
|
|
8a498391ca | ||
|
|
146348a4fe | ||
|
|
48b39f4712 | ||
|
|
3aee0b5e70 | ||
|
|
6d5c920a95 | ||
|
|
cdf04323a9 | ||
|
|
bdac68900f | ||
|
|
a5ae4c801c | ||
|
|
404913dcfa | ||
|
|
c94badbf36 | ||
|
|
ca1485f121 | ||
|
|
dfe874cf3f | ||
|
|
c20c9e2e78 | ||
|
|
f4f6fb6a7a | ||
|
|
ac8e09bc11 | ||
|
|
183ad87d07 | ||
|
|
f95d1ef058 | ||
|
|
61b64a7516 | ||
|
|
494f2f4821 | ||
|
|
d3937e5c80 | ||
|
|
3ac2ac34ed | ||
|
|
25907d8969 | ||
|
|
26b85052e1 | ||
|
|
07a7993109 | ||
|
|
7798b12086 | ||
|
|
be11a1a2f9 | ||
|
|
86d8133f82 | ||
|
|
6081db382c | ||
|
|
b89ab2c407 | ||
|
|
fce2d743e5 | ||
|
|
2a3fc8cfec | ||
|
|
7d1fc8cbe1 | ||
|
|
f969caa2d1 | ||
|
|
0fd86a6cc7 | ||
|
|
ab5dc7ddd5 | ||
|
|
3ce8a1abba | ||
|
|
834e5b702e | ||
|
|
001f329393 | ||
|
|
72549697a3 | ||
|
|
1e0356a74b | ||
|
|
42266397aa | ||
|
|
846cccf373 | ||
|
|
ad2506fe75 | ||
|
|
7dcd39986f | ||
|
|
b28f2908a6 | ||
|
|
7d9d510c0f | ||
|
|
c64f3590ad | ||
|
|
f0f478dfa0 | ||
|
|
ceaae89dee | ||
|
|
77a50eac42 | ||
|
|
877a5f27d1 | ||
|
|
2c0928ca20 | ||
|
|
4e686ecfcc | ||
|
|
35e42b28fe | ||
|
|
9137f68a57 | ||
|
|
6ac49a7694 | ||
|
|
c5066bb613 | ||
|
|
4a0dab3608 | ||
|
|
1b72b7258d | ||
|
|
58070a8b3e | ||
|
|
57653cb911 | ||
|
|
ae209f72b9 | ||
|
|
2859075e43 | ||
|
|
0e50009875 | ||
|
|
514a462f7b | ||
|
|
01cbd7ae9d | ||
|
|
f92b824f52 | ||
|
|
3adfb0db3f | ||
|
|
fd07830c02 | ||
|
|
9e986f25f1 | ||
|
|
e357a7b401 | ||
|
|
9f50253537 | ||
|
|
1e8767e8b5 | ||
|
|
a6add2eff6 | ||
|
|
25639a822a | ||
|
|
e1f8af6d5b | ||
|
|
e7b8648792 | ||
|
|
c819197d07 | ||
|
|
15fb493d9a | ||
|
|
cd6394987d | ||
|
|
0cf7d1a63d | ||
|
|
439c81d836 | ||
|
|
1e0d43e975 | ||
|
|
994baf12c4 | ||
|
|
d12a1371c2 | ||
|
|
f9e40ba586 | ||
|
|
a32fb752dd | ||
|
|
e4f30cea57 | ||
|
|
d0f4cc2ee2 | ||
|
|
c4c9c92d7e | ||
|
|
e6fbdb17e8 | ||
|
|
02f474e16a | ||
|
|
0861a4391e | ||
|
|
1731d4daa7 | ||
|
|
875557dc9d | ||
|
|
be8fa1f4e4 | ||
|
|
3d3013a592 | ||
|
|
4b440c83a4 | ||
|
|
f57cae9124 | ||
|
|
2231d4c6cf | ||
|
|
e29a4f9a8a | ||
|
|
64206bc35b | ||
|
|
e351c3e355 | ||
|
|
fc845a36f1 | ||
|
|
9bf3767093 | ||
|
|
8e0f2fcb35 | ||
|
|
00ee5a63df | ||
|
|
e068c4831b | ||
|
|
2a03477597 | ||
|
|
deebc31c34 | ||
|
|
9f1ff1fd01 | ||
|
|
f7229ab229 | ||
|
|
c2b68ed6b5 | ||
|
|
0a74bb8373 | ||
|
|
ef5ff3a663 | ||
|
|
d6e5c0b346 | ||
|
|
107474fc74 | ||
|
|
9a984963a7 | ||
|
|
805baa18a9 | ||
|
|
533b05384c | ||
|
|
9c2e67e953 | ||
|
|
522e646b36 | ||
|
|
3d8dceb76a | ||
|
|
b9316422d2 | ||
|
|
8d1899b13d | ||
|
|
8ff9ffbc38 | ||
|
|
961df756c5 | ||
|
|
736de4826f | ||
|
|
774245f540 | ||
|
|
a2ddf78842 | ||
|
|
f4ce0a4b81 | ||
|
|
a23a0a233e | ||
|
|
7dcf7ec5b0 | ||
|
|
b643829fe2 | ||
|
|
076a05f8a9 | ||
|
|
284103b6b6 | ||
|
|
dd099eae54 | ||
|
|
309781d5b1 | ||
|
|
2023a1a2fc | ||
|
|
d1ca9a6e14 | ||
|
|
fc463fd608 | ||
|
|
d89a05aec8 | ||
|
|
6dd31a947e | ||
|
|
5191877fbe | ||
|
|
f6af5098b0 | ||
|
|
7644f08d5c | ||
|
|
27b22acd37 | ||
|
|
50b84c4ced | ||
|
|
9160a3ff6b | ||
|
|
a57815edbb | ||
|
|
4c754e2cdb | ||
|
|
fcf2681abc | ||
|
|
ffcffb30ca | ||
|
|
cdff1ef7b6 | ||
|
|
d95d9df0f1 | ||
|
|
56fb50f644 | ||
|
|
f4cbd90400 | ||
|
|
9baaf1efc9 | ||
|
|
0196218d06 | ||
|
|
b253373d4d | ||
|
|
8f71b56c26 | ||
|
|
e8ee1dad04 | ||
|
|
dc2551d881 | ||
|
|
c167780cad | ||
|
|
534e69fde5 | ||
|
|
e92b17a341 | ||
|
|
1bd01c83a7 | ||
|
|
05bc2bd293 | ||
|
|
6f4c9070f6 | ||
|
|
198f63d0b3 | ||
|
|
a72da7036b | ||
|
|
3571b8c5fa | ||
|
|
91a2274fe5 | ||
|
|
0f2adaa8d2 | ||
|
|
c3e071b0d1 | ||
|
|
8c9765749e | ||
|
|
6cf23b46c5 | ||
|
|
7fa55fe5c6 | ||
|
|
21d8aafd97 | ||
|
|
fbd3d99b1b | ||
|
|
f14c36ed6b | ||
|
|
65db856054 | ||
|
|
8ab698d4dc | ||
|
|
5598a0d24f | ||
|
|
ef00dca5a0 | ||
|
|
7a308f1651 | ||
|
|
3edfd07a40 | ||
|
|
5e0186fa1f | ||
|
|
1c7e9923f9 | ||
|
|
a8928a0ccc | ||
|
|
2aad722b4b | ||
|
|
9ad6dce2d6 | ||
|
|
178aadb311 | ||
|
|
6f629e112a | ||
|
|
5b25f63e44 | ||
|
|
140d62939a | ||
|
|
95a7fc8ef5 | ||
|
|
3eff65f1f5 | ||
|
|
2a3dc33f86 | ||
|
|
6ea4aac361 | ||
|
|
0b35cb6619 | ||
|
|
9468dcb406 | ||
|
|
d5349e7ad0 | ||
|
|
a7132684e5 | ||
|
|
7eac6e725a | ||
|
|
aeae0f245e | ||
|
|
38d75d2b1c | ||
|
|
594bec1b37 | ||
|
|
1b711bcd46 | ||
|
|
4ad6b1a65e | ||
|
|
b701ca43f4 | ||
|
|
88563431b8 | ||
|
|
06fffb9ef7 | ||
|
|
ab0728cd0b | ||
|
|
44d7537744 | ||
|
|
6fadeacf0e | ||
|
|
af9376b60c | ||
|
|
a395f183f9 | ||
|
|
7c57d3d4c6 | ||
|
|
bbd43f7026 | ||
|
|
a94742e4db | ||
|
|
24cb823c90 | ||
|
|
8372317a8f | ||
|
|
ef08fd4bb3 | ||
|
|
1d58ef55f7 | ||
|
|
a1ccf8a28e | ||
|
|
7ab05cf857 | ||
|
|
c18c1c67d1 | ||
|
|
cd2d73810d | ||
|
|
91917886a8 | ||
|
|
8bbc0b7790 | ||
|
|
2e83ab80cf | ||
|
|
bba4b54f9b | ||
|
|
897eb11512 | ||
|
|
ac5fe6a9fb | ||
|
|
29760d6419 | ||
|
|
1808e3881f | ||
|
|
a9ea042791 | ||
|
|
6d5ca1501c | ||
|
|
946046e53b | ||
|
|
71b84d490e | ||
|
|
6bd5a895b3 | ||
|
|
e661430cc9 | ||
|
|
415955e7b3 | ||
|
|
5aa993f5b4 | ||
|
|
6934b87816 | ||
|
|
e4de7e262d | ||
|
|
d711c321b6 | ||
|
|
733dc76c6c | ||
|
|
4195bd6cd8 | ||
|
|
8c0bad3115 | ||
|
|
a9b9cbf4bd | ||
|
|
33e5601658 | ||
|
|
2a1ca1c206 | ||
|
|
357040f67a | ||
|
|
920f52e112 | ||
|
|
a25f2141a5 | ||
|
|
c51b956b01 | ||
|
|
0d845b0fd6 | ||
|
|
fe9f147ff0 | ||
|
|
2a5f598fb0 | ||
|
|
bf69ed0008 | ||
|
|
8bd952ed56 | ||
|
|
9a3f61904b | ||
|
|
fbc5318a7b | ||
|
|
41ce7047cc | ||
|
|
f28471e456 | ||
|
|
4cb9e3a3f1 | ||
|
|
2f6a249b5f | ||
|
|
0634735288 | ||
|
|
719c45b408 | ||
|
|
b70edd5424 | ||
|
|
a6498c2f96 | ||
|
|
56be7b1d46 | ||
|
|
b2f3477261 | ||
|
|
14b73149be | ||
|
|
0ab7d95607 | ||
|
|
ee08dcfeb4 | ||
|
|
b893dea810 | ||
|
|
ec5ce45850 | ||
|
|
9afb97fa0f | ||
|
|
676abe0ced | ||
|
|
73d38cb91b | ||
|
|
fffae46a63 | ||
|
|
6ed91cab1f | ||
|
|
cc5d0c35dd | ||
|
|
c34570154c | ||
|
|
a5940e1641 | ||
|
|
39f0c5b5b0 | ||
|
|
abb5adec43 | ||
|
|
525cb4826f | ||
|
|
fde0aba96c | ||
|
|
ff18fd25f1 | ||
|
|
9248ac05ac | ||
|
|
a066c6391d | ||
|
|
4d11485283 | ||
|
|
9e270690ef | ||
|
|
15b781b271 | ||
|
|
5dc8f21b7b | ||
|
|
9ccb3ee80b | ||
|
|
27de66b055 | ||
|
|
ba98c7e2c5 | ||
|
|
22eae753fe | ||
|
|
d832d850fe | ||
|
|
aead867ea0 | ||
|
|
97f5022bdd | ||
|
|
0cb7a555d3 | ||
|
|
52b7872a55 | ||
|
|
522aaee1a3 | ||
|
|
179cf6e484 | ||
|
|
28ded1f0c2 | ||
|
|
7d971fc39d | ||
|
|
4f0b20e8ad | ||
|
|
a6f2ee1367 | ||
|
|
eb1c598a6c | ||
|
|
4706bf0528 | ||
|
|
969b6caa96 | ||
|
|
69ea1e6d26 | ||
|
|
91704d9df7 | ||
|
|
dbbc2ddb1c | ||
|
|
99729457cc | ||
|
|
5a58294bc6 | ||
|
|
398b3bbd8b | ||
|
|
6cb038c362 | ||
|
|
cc40948783 | ||
|
|
00bdcd3948 | ||
|
|
c860ffc176 | ||
|
|
8664411880 | ||
|
|
f17f1008e3 | ||
|
|
a2828f3b9a | ||
|
|
cbfdfb43e3 | ||
|
|
23e672aef9 | ||
|
|
6d9cc7e29d | ||
|
|
8a47788a09 | ||
|
|
afed5ab666 | ||
|
|
357eda8c19 | ||
|
|
f18401d183 | ||
|
|
4ea91d14f9 | ||
|
|
f57661b13f | ||
|
|
ad25c1d1b2 | ||
|
|
87af5dcee5 | ||
|
|
106871b956 | ||
|
|
4d25abcfce | ||
|
|
2ccdf3c97a | ||
|
|
89bd9c8038 | ||
|
|
88627dc837 | ||
|
|
8ca57b0705 | ||
|
|
c7db283e8c | ||
|
|
83ca3b7b8b | ||
|
|
830699d2b8 | ||
|
|
f822e658c4 | ||
|
|
8817a1afb7 | ||
|
|
693adf181e | ||
|
|
f269f13b09 | ||
|
|
9845258a25 | ||
|
|
edbed2c8d3 | ||
|
|
8e0f2d2500 | ||
|
|
e022504c26 | ||
|
|
62e4cbd052 | ||
|
|
70ae59550d | ||
|
|
f74af8fa2d | ||
|
|
82d1b57005 | ||
|
|
c32aacc1b3 | ||
|
|
523b4045bf | ||
|
|
8e4e273b7c | ||
|
|
816297e22f | ||
|
|
72889b5c36 | ||
|
|
0f0216fe79 | ||
|
|
42433d1ad4 | ||
|
|
52533fc04c | ||
|
|
bb0223877c | ||
|
|
5eb1fcddbb | ||
|
|
c646eb3939 | ||
|
|
a313c99370 | ||
|
|
0f84d9f02e | ||
|
|
900a9c6145 | ||
|
|
5b33cbe9aa | ||
|
|
114ce3b764 | ||
|
|
660d3f326f | ||
|
|
b8d51ae0de | ||
|
|
0bdda6387a | ||
|
|
4fbdbb1aa2 | ||
|
|
72ddcb4fff | ||
|
|
50ef2de5f9 | ||
|
|
55d3ee1af0 | ||
|
|
422166441e | ||
|
|
9d3f85628c | ||
|
|
669d9c3c66 | ||
|
|
dcb406d246 | ||
|
|
cadad28b0c | ||
|
|
01b0a033fd | ||
|
|
0fb66ab258 | ||
|
|
a49c21cfd1 | ||
|
|
f67a8c1f2d | ||
|
|
f4624ead42 | ||
|
|
2cd570383f | ||
|
|
920900b619 | ||
|
|
e98d934a67 | ||
|
|
31a846b9c3 | ||
|
|
5eaea28401 | ||
|
|
50ef902adb | ||
|
|
75b6a078c6 | ||
|
|
c0c93c172e | ||
|
|
ed18244070 | ||
|
|
e13063e0c6 | ||
|
|
6c38997010 | ||
|
|
0e01c0d69b | ||
|
|
caab3ea74d | ||
|
|
c543dff2e1 | ||
|
|
92badfd88c | ||
|
|
dca64e6939 | ||
|
|
a9c4d27d5e | ||
|
|
610c2f9519 | ||
|
|
05d757e7c4 | ||
|
|
31a2453882 | ||
|
|
5febd0a0d6 | ||
|
|
694f1e9b25 | ||
|
|
131bf842a9 | ||
|
|
8ec1c2e04a | ||
|
|
e94dc257a1 | ||
|
|
3bd4fc59d4 | ||
|
|
7b8463b03a | ||
|
|
00e7fc1c0d | ||
|
|
2ca20ad701 | ||
|
|
775da82072 | ||
|
|
162b392004 | ||
|
|
26bedf0523 | ||
|
|
ff3ee62509 | ||
|
|
9c2a78adf2 | ||
|
|
5a767ba3ef | ||
|
|
691d642721 | ||
|
|
7dbfc3740d | ||
|
|
b2897d7feb | ||
|
|
b18177c215 | ||
|
|
cec0a8c2e7 | ||
|
|
412de318ed | ||
|
|
92cc7a4648 | ||
|
|
96c0481e17 | ||
|
|
5dd7ddc288 | ||
|
|
ea91a82f30 | ||
|
|
8e10269b50 | ||
|
|
dae74666c5 | ||
|
|
94e31e35ba | ||
|
|
c835b4eb1a | ||
|
|
ef9e43fbd3 | ||
|
|
f083433854 | ||
|
|
9052b1c3db | ||
|
|
59578a73af | ||
|
|
c691e260cf | ||
|
|
82072c8970 | ||
|
|
d0c52ac176 | ||
|
|
6811a62568 | ||
|
|
8653d03969 | ||
|
|
90d5a04368 | ||
|
|
84e4ebef08 | ||
|
|
98603c4042 | ||
|
|
26a4ee0171 | ||
|
|
4f03a2d25c | ||
|
|
6a830a3843 | ||
|
|
3ffd049135 | ||
|
|
e6d1b38b82 | ||
|
|
f8a892faf2 | ||
|
|
54e141489a | ||
|
|
e64fd1d308 | ||
|
|
01647c3df9 | ||
|
|
cd6d7c76f6 | ||
|
|
efa71c4ac8 | ||
|
|
d4eb27a4ed | ||
|
|
eca18ba6ee | ||
|
|
31fa49feed | ||
|
|
b68aafdb72 | ||
|
|
fd09a63e48 | ||
|
|
afc50863cd | ||
|
|
fea2240c39 |
@@ -1,14 +1,36 @@
|
||||
engines:
|
||||
version: "2"
|
||||
plugins:
|
||||
rubocop:
|
||||
enabled: true
|
||||
channel: rubocop-0-48
|
||||
channel: "rubocop-0-48"
|
||||
scss-lint:
|
||||
enabled: false
|
||||
ratings:
|
||||
paths:
|
||||
- app/**
|
||||
- lib/**
|
||||
- "**.rb"
|
||||
exclude_paths:
|
||||
- spec/**/*
|
||||
- vendor/**/*
|
||||
duplication:
|
||||
enabled: true
|
||||
exclude_patterns:
|
||||
- "db/**"
|
||||
- "config/initializers/active_record_postgresql_referential_integrity_patch.rb"
|
||||
checks:
|
||||
argument-count:
|
||||
enabled: false
|
||||
complex-logic:
|
||||
enabled: true
|
||||
file-lines:
|
||||
enabled: false
|
||||
method-complexity:
|
||||
enabled: false
|
||||
method-count:
|
||||
enabled: false
|
||||
method-lines:
|
||||
enabled: false
|
||||
nested-control-flow:
|
||||
enabled: true
|
||||
return-statements:
|
||||
enabled: true
|
||||
similar-code:
|
||||
enabled: true
|
||||
identical-code:
|
||||
enabled: true
|
||||
exclude_patterns:
|
||||
- "spec/**/*"
|
||||
- "vendor/**/*"
|
||||
|
||||
42
.github/ISSUE_TEMPLATE.md
vendored
Normal file
42
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
<!--- If what you want to file is not a bug, please use the [Feature
|
||||
template](https://github.com/openfoodfoundation/openfoodnetwork/wiki/Feature-template)
|
||||
instead -->
|
||||
|
||||
<!--- Provide a general summary of the issue in the Title above -->
|
||||
|
||||
## 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
|
||||
<!--- Use the [Bug severity
|
||||
guideline](https://github.com/openfoodfoundation/openfoodnetwork/wiki/Bug-severity) to assign one to this bug -->
|
||||
|
||||
## Your Environment
|
||||
<!--- Include as many 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 -->
|
||||
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,5 +1,7 @@
|
||||
#### What? Why?
|
||||
|
||||
Closes #[the issue number this PR is related to]
|
||||
|
||||
[Explain why is this change needed and the solution you propose. Provide
|
||||
context for others to understand it]
|
||||
|
||||
|
||||
@@ -27,6 +27,10 @@ Style/Documentation:
|
||||
Style/StringLiterals:
|
||||
Enabled: false
|
||||
|
||||
Style/HashSyntax:
|
||||
Enabled: true
|
||||
EnforcedStyle: ruby19_no_mixed_keys
|
||||
|
||||
Layout/MultilineMethodCallIndentation:
|
||||
Enabled: true
|
||||
EnforcedStyle: indented
|
||||
@@ -53,6 +57,10 @@ Lint/UselessAssignment:
|
||||
Rails/DynamicFindBy:
|
||||
Enabled: false
|
||||
|
||||
# Same as above, #find_by is not available until Rails 4
|
||||
Rails/FindBy:
|
||||
Enabled: false
|
||||
|
||||
# This should be the programmer's discretion, perhaps we should review all of
|
||||
# the uses of it an make specific exceptions though.
|
||||
Rails/SkipsModelValidations:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,8 @@ cache: bundler
|
||||
bundler_args: --without development
|
||||
rvm:
|
||||
- "2.1.5"
|
||||
addons:
|
||||
postgresql: "9.5"
|
||||
|
||||
# Set the timezone for phantomjs with TZ
|
||||
# Set the timezone for karma with TIMEZONE
|
||||
@@ -22,9 +24,6 @@ env:
|
||||
- CI_NODE_INDEX=3
|
||||
- CI_NODE_INDEX=4 KARMA="true" GITHUB_DEPLOY="true"
|
||||
|
||||
before_install:
|
||||
- ./script/upgrade_bundler.sh
|
||||
|
||||
before_script:
|
||||
- cp config/database.travis.yml config/database.yml
|
||||
- cp config/application.yml.example config/application.yml
|
||||
@@ -43,7 +42,6 @@ before_script:
|
||||
|
||||
script:
|
||||
- 'if [ "$KARMA" = "true" ]; then bundle exec rake karma:run; else echo "Skipping karma run"; fi'
|
||||
#- "KNAPSACK_GENERATE_REPORT=true bundle exec rspec spec"
|
||||
- "bundle exec rake 'knapsack:rspec[--tag ~performance]'"
|
||||
|
||||
after_success:
|
||||
|
||||
@@ -1,36 +1,68 @@
|
||||
See this here post on raising a github issue:
|
||||
https://community.openfoodnetwork.org/t/how-to-raise-a-github-issue/912
|
||||
|
||||
# Contributing
|
||||
We love pull requests from everyone. Any contribution is valuable, but there are two issue streams that we especially love people to work on:
|
||||
|
||||
We love pull requests from everyone. Here are some instructions for
|
||||
contributing code to Open Food Network. See the [developer wiki](https://github.com/openfoodfoundation/openfoodnetwork/wiki) for more information.
|
||||
1) Our delivery backlog, is managed via a ZenHub board (ZenHub extensions are available for most major browsers). We use a Kanban-style approach, whereby devs pick issues from the top of the backlog which has been organised according to current priorities. If you have some time and are interested in working on some issues from the backlog, please make yourself known on the [#dev](https://openfoodnetwork.slack.com/messages/C2GQ45KNU) channel on Slack and we can direct you to the most appropriate issue to pick up.
|
||||
|
||||
Fork, then clone the repo:
|
||||
2) Our list of bugs and other self-contained issues that we consider to be a good starting point for new contributors, or devs who aren’t able to commit to seeing a whole feature through. These issues are marked with the `# good first issue` label.
|
||||
|
||||
git clone git@github.com:your-username/openfoodnetwork.git
|
||||
## Set up
|
||||
|
||||
Follow the instructions in README.markdown to set up your machine.
|
||||
Set up your local development environment by following the appropriate guide from the `Development environment setup` section in the [developer wiki](https://github.com/openfoodfoundation/openfoodnetwork/wiki).
|
||||
|
||||
Make sure the tests pass:
|
||||
Add an `upstream` remote that points to the main repo:
|
||||
|
||||
rspec spec
|
||||
cd ~/location-of-your-local-ofn-repo
|
||||
git remote add upstream https://github.com/openfoodfoundation/openfoodnetwork
|
||||
|
||||
Make your change. Add tests for your change. Make the tests pass:
|
||||
If you haven't already done so, fork this repo using the `Fork` button in the top-right corner of this screen. Then ensure that your fork is listed as the `origin` remote on your local machine.
|
||||
|
||||
rspec spec
|
||||
git remote set-url origin https://github.com/your-username/openfoodnetwork
|
||||
|
||||
Push to your fork and [submit a pull request][pr].
|
||||
Fetch the latest version of `master` from `upstream` (ie. the main repo):
|
||||
|
||||
[pr]: https://github.com/openfoodfoundation/openfoodnetwork/compare/
|
||||
git fetch upstream master
|
||||
|
||||
At this point you're waiting on us. We may suggest some changes or
|
||||
improvements or alternatives.
|
||||
Create a new branch on your local machine for (based on `upstream/master`):
|
||||
|
||||
To increase the chance that your pull request is swiftly accepted:
|
||||
git checkout -b branch-name-here --no-track upstream/master
|
||||
|
||||
If you want to run the whole test suite, we recommend using a free CI service to run your tests in parallel. Running the whole suite locally in series is likely to take > 40 minutes. [TravisCI][travis] and [SemaphoreCI][semaphore] both work great in our experience. Either way, make sure the tests pass on your new branch:
|
||||
|
||||
bundle exec rspec spec
|
||||
|
||||
## Making a change
|
||||
|
||||
Make your changes to the codebase. We recommend using TDD. Add a test, make changes and get the test suite back to green.
|
||||
|
||||
bundle exec rspec spec
|
||||
|
||||
Once the tests are passing you can commit your changes. See [Making a great commit][great-commit] for more tips.
|
||||
|
||||
git add .
|
||||
git commit -m "Add a concise commit message describing your change here"
|
||||
|
||||
Push your changes to a branch on your fork:
|
||||
|
||||
git push origin branch-name-here
|
||||
|
||||
## Submitting a Pull Request
|
||||
|
||||
Use the GitHub UI to submit a [new pull request][pr] against upstream/master. To increase the chances that your pull request is swiftly accepted please have a look at our guide to [[making a great pull request]].
|
||||
|
||||
TL;DR:
|
||||
* Write tests
|
||||
* Make sure the whole test suite is passing
|
||||
* Keep your PR small, with a single focus
|
||||
* Maintain a clean commit history
|
||||
* Use a style consistent with the rest of the codebase
|
||||
* Before submitting, [rebase your work][rebase] on the current master branch
|
||||
|
||||
From here, your pull request will progress through the [Review, Test, Merge & Deploy process][process].
|
||||
|
||||
[pr]: https://github.com/openfoodfoundation/openfoodnetwork/compare/
|
||||
[great-pr]: https://github.com/openfoodfoundation/openfoodnetwork/wiki/Making-a-great-pull-request
|
||||
[great-commit]: https://github.com/openfoodfoundation/openfoodnetwork/wiki/Making-a-great-commit
|
||||
[process]: https://github.com/openfoodfoundation/openfoodnetwork/wiki/The-process-of-review%2C-test%2C-merge-and-deploy
|
||||
[rebase]: https://www.atlassian.com/git/tutorials/merging-vs-rebasing/workflow-walkthrough
|
||||
[travis]: https://travis-ci.org/
|
||||
[semaphore]: https://semaphoreci.com/
|
||||
|
||||
38
Gemfile
38
Gemfile
@@ -1,5 +1,6 @@
|
||||
source 'https://rubygems.org'
|
||||
ruby "2.1.5"
|
||||
git_source(:github) { |repo_name| "https://github.com/#{repo_name}.git" }
|
||||
|
||||
gem 'rails', '3.2.21'
|
||||
gem 'rails-i18n', '~> 3.0.0'
|
||||
@@ -10,15 +11,15 @@ gem 'i18n-js', '~> 3.0.0'
|
||||
gem 'nokogiri', '>= 1.6.7.1'
|
||||
|
||||
gem 'pg'
|
||||
gem 'spree', github: 'openfoodfoundation/spree', branch: 'step-6a', ref: '5a76d45'
|
||||
gem 'spree', github: 'openfoodfoundation/spree', branch: 'step-6a', ref: '86bf87f1b1e1b299edc8cd10a2486e44ba0a3987'
|
||||
gem 'spree_i18n', github: 'spree/spree_i18n', branch: '1-3-stable'
|
||||
gem 'spree_auth_devise', github: 'openfoodfoundation/spree_auth_devise', branch: 'spree-upgrade-intermediate'
|
||||
|
||||
# Our branch contains two changes
|
||||
# - Pass customer email and phone number to PayPal (merged to upstream master)
|
||||
# - Change type of password from string to password to hide it in the form
|
||||
gem 'spree_paypal_express', :github => "openfoodfoundation/better_spree_paypal_express", :branch => "spree-upgrade-intermediate"
|
||||
#gem 'spree_paypal_express', :github => "spree-contrib/better_spree_paypal_express", :branch => "1-3-stable"
|
||||
gem 'spree_paypal_express', github: "openfoodfoundation/better_spree_paypal_express", branch: "spree-upgrade-intermediate"
|
||||
#gem 'spree_paypal_express', github: "spree-contrib/better_spree_paypal_express", branch: "1-3-stable"
|
||||
gem 'stripe', '~> 3.3.1'
|
||||
gem 'activemerchant', '~> 1.71.0'
|
||||
|
||||
@@ -30,7 +31,7 @@ gem 'daemons'
|
||||
|
||||
# Fix bug in simple_form preventing collection_check_boxes usage within form_for block
|
||||
# When merged, revert to upstream gem
|
||||
gem 'simple_form', :github => 'RohanM/simple_form'
|
||||
gem 'simple_form', github: 'RohanM/simple_form'
|
||||
|
||||
gem 'unicorn'
|
||||
gem 'angularjs-rails', '1.5.5'
|
||||
@@ -48,14 +49,14 @@ gem 'representative_view'
|
||||
gem 'rabl'
|
||||
gem "active_model_serializers"
|
||||
gem 'oj'
|
||||
gem 'deface', :github => 'spree/deface', :ref => '1110a13'
|
||||
gem 'deface', github: 'spree/deface', ref: '1110a13'
|
||||
gem 'paperclip'
|
||||
gem 'dalli'
|
||||
gem 'geocoder'
|
||||
gem 'gmaps4rails'
|
||||
gem 'spinjs-rails'
|
||||
gem 'rack-ssl', :require => 'rack/ssl'
|
||||
gem 'custom_error_message', :github => 'jeremydurham/custom-err-msg'
|
||||
gem 'rack-ssl', require: 'rack/ssl'
|
||||
gem 'custom_error_message', github: 'jeremydurham/custom-err-msg'
|
||||
gem 'angularjs-file-upload-rails', '~> 1.1.6'
|
||||
gem 'roadie-rails', '~> 1.0.3'
|
||||
gem 'figaro'
|
||||
@@ -63,6 +64,7 @@ gem 'blockenspiel'
|
||||
gem 'acts-as-taggable-on', '~> 3.4'
|
||||
gem 'paper_trail', '~> 3.0.8'
|
||||
gem 'diffy'
|
||||
gem 'skylight', '< 2.0'
|
||||
|
||||
gem 'wicked_pdf'
|
||||
gem 'wkhtmltopdf-binary'
|
||||
@@ -97,23 +99,22 @@ gem 'jquery-rails'
|
||||
gem 'jquery-migrate-rails'
|
||||
gem 'css_splitter'
|
||||
|
||||
gem 'ofn-qz', github: 'openfoodfoundation/ofn-qz'
|
||||
gem 'ofn-qz', github: 'openfoodfoundation/ofn-qz', ref: '60da2ae4c44cbb4c8d602f59fb5fff8d0f21db3c'
|
||||
|
||||
group :test, :development do
|
||||
# Pretty printed test output
|
||||
gem 'turn', '~> 0.8.3', :require => false
|
||||
gem 'fuubar'
|
||||
gem 'rspec-rails'
|
||||
gem 'fuubar', '~> 2.2.0'
|
||||
gem 'rspec-rails', ">= 3.5.2"
|
||||
gem 'shoulda-matchers'
|
||||
gem 'factory_girl_rails', :require => false
|
||||
gem 'capybara'
|
||||
gem 'database_cleaner', '0.7.1', :require => false
|
||||
gem 'factory_girl_rails', require: false
|
||||
gem 'capybara', '>= 2.15.4'
|
||||
gem 'database_cleaner', '0.7.1', require: false
|
||||
gem 'awesome_print'
|
||||
gem 'letter_opener'
|
||||
gem 'letter_opener', '>= 1.4.1'
|
||||
gem 'timecop'
|
||||
gem 'poltergeist'
|
||||
gem 'poltergeist', '>= 1.16.0'
|
||||
gem 'rspec-retry'
|
||||
gem 'json_spec'
|
||||
gem 'json_spec', '~> 1.1.4'
|
||||
gem 'unicorn-rails'
|
||||
gem 'atomic'
|
||||
gem 'knapsack'
|
||||
@@ -130,10 +131,11 @@ group :development do
|
||||
gem 'pry-byebug', '>= 3.4.3'
|
||||
gem 'debugger-linecache'
|
||||
gem 'guard'
|
||||
gem 'listen', '3.0.8' # 3.1.0 requires ruby 2.2
|
||||
gem 'guard-livereload'
|
||||
gem 'rack-livereload'
|
||||
gem 'guard-rails'
|
||||
gem 'guard-rspec'
|
||||
gem 'guard-rspec', '~> 4.7.3'
|
||||
gem 'parallel_tests'
|
||||
gem 'rubocop', '>= 0.49.1'
|
||||
|
||||
|
||||
195
Gemfile.lock
195
Gemfile.lock
@@ -1,5 +1,5 @@
|
||||
GIT
|
||||
remote: git://github.com/RohanM/simple_form.git
|
||||
remote: https://github.com/RohanM/simple_form.git
|
||||
revision: 45f08a213b40f3d4bda5f5398db841137587160a
|
||||
specs:
|
||||
simple_form (2.0.2)
|
||||
@@ -7,13 +7,13 @@ GIT
|
||||
activemodel (~> 3.0)
|
||||
|
||||
GIT
|
||||
remote: git://github.com/jeremydurham/custom-err-msg.git
|
||||
remote: https://github.com/jeremydurham/custom-err-msg.git
|
||||
revision: 3a8ec9dddc7a5b0aab7c69a6060596de300c68f4
|
||||
specs:
|
||||
custom_error_message (1.1.1)
|
||||
|
||||
GIT
|
||||
remote: git://github.com/openfoodfoundation/better_spree_paypal_express.git
|
||||
remote: https://github.com/openfoodfoundation/better_spree_paypal_express.git
|
||||
revision: 8d95f4544c682634812becaf50999fba0cd04df0
|
||||
branch: spree-upgrade-intermediate
|
||||
specs:
|
||||
@@ -22,16 +22,17 @@ GIT
|
||||
spree_core (~> 1.3.99)
|
||||
|
||||
GIT
|
||||
remote: git://github.com/openfoodfoundation/ofn-qz.git
|
||||
revision: 024680ccea429b2e5428d7b964fa67c52add34ec
|
||||
remote: https://github.com/openfoodfoundation/ofn-qz.git
|
||||
revision: 60da2ae4c44cbb4c8d602f59fb5fff8d0f21db3c
|
||||
ref: 60da2ae4c44cbb4c8d602f59fb5fff8d0f21db3c
|
||||
specs:
|
||||
ofn-qz (0.1.0)
|
||||
railties (~> 3.1)
|
||||
|
||||
GIT
|
||||
remote: git://github.com/openfoodfoundation/spree.git
|
||||
revision: 5a76d456ff70aea7aae3d25156558d71eb7febf2
|
||||
ref: 5a76d45
|
||||
remote: https://github.com/openfoodfoundation/spree.git
|
||||
revision: 86bf87f1b1e1b299edc8cd10a2486e44ba0a3987
|
||||
ref: 86bf87f1b1e1b299edc8cd10a2486e44ba0a3987
|
||||
branch: step-6a
|
||||
specs:
|
||||
spree (1.3.99)
|
||||
@@ -91,7 +92,7 @@ GIT
|
||||
spree_core (= 1.3.99)
|
||||
|
||||
GIT
|
||||
remote: git://github.com/openfoodfoundation/spree_auth_devise.git
|
||||
remote: https://github.com/openfoodfoundation/spree_auth_devise.git
|
||||
revision: da9eecefc6fe13dedf4c6f3febec79caad839ec3
|
||||
branch: spree-upgrade-intermediate
|
||||
specs:
|
||||
@@ -103,7 +104,7 @@ GIT
|
||||
spree_frontend (~> 1.3.6)
|
||||
|
||||
GIT
|
||||
remote: git://github.com/spree/deface.git
|
||||
remote: https://github.com/spree/deface.git
|
||||
revision: 1110a1336252109bce7f98f9182042e0bc2930ae
|
||||
ref: 1110a13
|
||||
specs:
|
||||
@@ -113,7 +114,7 @@ GIT
|
||||
rails (>= 3.1)
|
||||
|
||||
GIT
|
||||
remote: git://github.com/spree/spree_i18n.git
|
||||
remote: https://github.com/spree/spree_i18n.git
|
||||
revision: 752eb67204e9c5a4e22b62591a8fd55fe2285e43
|
||||
branch: 1-3-stable
|
||||
specs:
|
||||
@@ -123,7 +124,7 @@ GIT
|
||||
spree_core (>= 1.1)
|
||||
|
||||
GIT
|
||||
remote: git://github.com/willrjmarshall/foundation_rails_helper.git
|
||||
remote: https://github.com/willrjmarshall/foundation_rails_helper.git
|
||||
revision: 4d5d53fdc4b1fb71e66524d298c5c635de82cfbb
|
||||
branch: rails3
|
||||
specs:
|
||||
@@ -173,7 +174,8 @@ GEM
|
||||
acts-as-taggable-on (3.5.0)
|
||||
activerecord (>= 3.2, < 5)
|
||||
acts_as_list (0.1.9)
|
||||
addressable (2.4.0)
|
||||
addressable (2.5.2)
|
||||
public_suffix (>= 2.0.2, < 4.0)
|
||||
andand (1.3.3)
|
||||
angular-rails-templates (0.2.0)
|
||||
railties (>= 3.1)
|
||||
@@ -181,7 +183,6 @@ GEM
|
||||
tilt
|
||||
angularjs-file-upload-rails (1.1.6)
|
||||
angularjs-rails (1.5.5)
|
||||
ansi (1.4.2)
|
||||
arel (3.0.3)
|
||||
ast (2.3.0)
|
||||
atomic (1.1.99)
|
||||
@@ -200,15 +201,13 @@ GEM
|
||||
builder (3.0.4)
|
||||
byebug (9.0.6)
|
||||
cancan (1.6.8)
|
||||
capybara (2.7.1)
|
||||
capybara (2.18.0)
|
||||
addressable
|
||||
mime-types (>= 1.16)
|
||||
mini_mime (>= 0.1.3)
|
||||
nokogiri (>= 1.3.3)
|
||||
rack (>= 1.0.0)
|
||||
rack-test (>= 0.5.4)
|
||||
xpath (~> 2.0)
|
||||
celluloid (0.15.2)
|
||||
timers (~> 1.1.0)
|
||||
xpath (>= 2.0, < 4.0)
|
||||
chronic (0.10.2)
|
||||
chunky_png (1.3.4)
|
||||
climate_control (0.1.0)
|
||||
@@ -266,24 +265,24 @@ GEM
|
||||
warden (~> 1.2.1)
|
||||
devise-encryptable (0.1.2)
|
||||
devise (>= 2.1.0)
|
||||
diff-lcs (1.2.4)
|
||||
diff-lcs (1.3)
|
||||
diffy (3.1.0)
|
||||
em-websocket (0.5.0)
|
||||
em-websocket (0.5.1)
|
||||
eventmachine (>= 0.12.9)
|
||||
http_parser.rb (~> 0.5.3)
|
||||
http_parser.rb (~> 0.6.0)
|
||||
erubis (2.7.0)
|
||||
eventmachine (1.2.3)
|
||||
excon (0.45.4)
|
||||
execjs (2.6.0)
|
||||
factory_girl (3.3.0)
|
||||
factory_girl (4.9.0)
|
||||
activesupport (>= 3.0.0)
|
||||
factory_girl_rails (3.3.0)
|
||||
factory_girl (~> 3.3.0)
|
||||
factory_girl_rails (4.9.0)
|
||||
factory_girl (~> 4.9.0)
|
||||
railties (>= 3.0.0)
|
||||
faraday (0.9.2)
|
||||
multipart-post (>= 1.2, < 3)
|
||||
ffaker (1.15.0)
|
||||
ffi (1.9.3)
|
||||
ffi (1.9.18)
|
||||
figaro (0.7.0)
|
||||
bundler (~> 1.0)
|
||||
rails (>= 3, < 5)
|
||||
@@ -404,31 +403,38 @@ GEM
|
||||
foundation-rails (5.5.0.0)
|
||||
railties (>= 3.1.0)
|
||||
sass (>= 3.2.0, < 3.4)
|
||||
fuubar (1.3.3)
|
||||
rspec (>= 2.14.0, < 3.1.0)
|
||||
fuubar (2.2.0)
|
||||
rspec-core (~> 3.0)
|
||||
ruby-progressbar (~> 1.4)
|
||||
geocoder (1.1.8)
|
||||
gmaps4rails (1.5.6)
|
||||
guard (2.2.4)
|
||||
guard (2.14.1)
|
||||
formatador (>= 0.2.4)
|
||||
listen (~> 2.1)
|
||||
listen (>= 2.7, < 4.0)
|
||||
lumberjack (~> 1.0)
|
||||
nenv (~> 0.1)
|
||||
notiffany (~> 0.0)
|
||||
pry (>= 0.9.12)
|
||||
shellany (~> 0.0)
|
||||
thor (>= 0.18.1)
|
||||
guard-livereload (2.0.1)
|
||||
guard-compat (1.2.1)
|
||||
guard-livereload (2.5.2)
|
||||
em-websocket (~> 0.5)
|
||||
guard (~> 2.0)
|
||||
guard (~> 2.8)
|
||||
guard-compat (~> 1.0)
|
||||
multi_json (~> 1.8)
|
||||
guard-rails (0.4.7)
|
||||
guard (>= 0.2.2)
|
||||
guard-rspec (4.0.4)
|
||||
guard (>= 2.1.1)
|
||||
rspec (~> 2.14)
|
||||
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.4)
|
||||
tilt
|
||||
highline (1.6.15)
|
||||
hike (1.2.3)
|
||||
http_parser.rb (0.5.3)
|
||||
http_parser.rb (0.6.0)
|
||||
httparty (0.9.0)
|
||||
multi_json (~> 1.0)
|
||||
multi_xml
|
||||
@@ -446,33 +452,32 @@ GEM
|
||||
railties (>= 3.0, < 5.0)
|
||||
thor (>= 0.14, < 2.0)
|
||||
json (1.8.6)
|
||||
json_spec (1.1.1)
|
||||
json_spec (1.1.5)
|
||||
multi_json (~> 1.0)
|
||||
rspec (~> 2.0)
|
||||
rspec (>= 2.0, < 4.0)
|
||||
jwt (1.5.4)
|
||||
kaminari (0.13.0)
|
||||
actionpack (>= 3.0.0)
|
||||
activesupport (>= 3.0.0)
|
||||
railties (>= 3.0.0)
|
||||
kgio (2.9.3)
|
||||
knapsack (1.5.1)
|
||||
knapsack (1.16.0)
|
||||
rake
|
||||
timecop (>= 0.1.0)
|
||||
launchy (2.1.2)
|
||||
launchy (2.4.3)
|
||||
addressable (~> 2.3)
|
||||
letter_opener (1.0.0)
|
||||
launchy (>= 2.0.4)
|
||||
letter_opener (1.6.0)
|
||||
launchy (~> 2.2)
|
||||
libv8 (3.16.14.11)
|
||||
listen (2.2.0)
|
||||
celluloid (>= 0.15.2)
|
||||
rb-fsevent (>= 0.9.3)
|
||||
rb-inotify (>= 0.9)
|
||||
lumberjack (1.0.4)
|
||||
listen (3.0.8)
|
||||
rb-fsevent (~> 0.9, >= 0.9.4)
|
||||
rb-inotify (~> 0.9, >= 0.9.7)
|
||||
lumberjack (1.0.12)
|
||||
mail (2.5.4)
|
||||
mime-types (~> 1.16)
|
||||
treetop (~> 1.4.8)
|
||||
method_source (0.9.0)
|
||||
mime-types (1.25.1)
|
||||
mini_mime (0.1.4)
|
||||
mini_portile2 (2.1.0)
|
||||
momentjs-rails (2.5.1)
|
||||
railties (>= 3.1)
|
||||
@@ -481,9 +486,13 @@ GEM
|
||||
multi_json (1.12.1)
|
||||
multi_xml (0.6.0)
|
||||
multipart-post (2.0.0)
|
||||
nenv (0.3.0)
|
||||
newrelic_rpm (3.12.0.288)
|
||||
nokogiri (1.6.8.1)
|
||||
mini_portile2 (~> 2.1.0)
|
||||
notiffany (0.1.1)
|
||||
nenv (~> 0.1)
|
||||
shellany (~> 0.0)
|
||||
oauth2 (1.2.0)
|
||||
faraday (>= 0.8, < 0.10)
|
||||
jwt (~> 1.0)
|
||||
@@ -511,28 +520,28 @@ GEM
|
||||
paypal-sdk-merchant (1.106.1)
|
||||
paypal-sdk-core (~> 0.2.3)
|
||||
pg (0.13.2)
|
||||
poltergeist (1.9.0)
|
||||
poltergeist (1.16.0)
|
||||
capybara (~> 2.1)
|
||||
cliver (~> 0.3.1)
|
||||
multi_json (~> 1.0)
|
||||
websocket-driver (>= 0.2.0)
|
||||
polyamorous (0.5.0)
|
||||
activerecord (~> 3.0)
|
||||
polyglot (0.3.5)
|
||||
powerpack (0.1.1)
|
||||
pry (0.11.1)
|
||||
pry (0.11.2)
|
||||
coderay (~> 1.1.0)
|
||||
method_source (~> 0.9.0)
|
||||
pry-byebug (3.4.3)
|
||||
byebug (>= 9.0, < 9.1)
|
||||
pry (~> 0.10)
|
||||
public_suffix (3.0.0)
|
||||
rabl (0.7.2)
|
||||
activesupport (>= 2.3.14)
|
||||
multi_json (~> 1.0)
|
||||
rack (1.4.7)
|
||||
rack-cache (1.7.0)
|
||||
rack (>= 0.4)
|
||||
rack-livereload (0.3.15)
|
||||
rack-livereload (0.3.16)
|
||||
rack
|
||||
rack-ssl (1.3.4)
|
||||
rack
|
||||
@@ -564,9 +573,9 @@ GEM
|
||||
actionpack (~> 3.0)
|
||||
activerecord (~> 3.0)
|
||||
polyamorous (~> 0.5.0)
|
||||
rb-fsevent (0.9.3)
|
||||
rb-inotify (0.9.2)
|
||||
ffi (>= 0.5.0)
|
||||
rb-fsevent (0.10.2)
|
||||
rb-inotify (0.9.10)
|
||||
ffi (>= 0.5.0, < 2)
|
||||
rdoc (3.12.2)
|
||||
json (~> 1.4)
|
||||
redcarpet (3.2.3)
|
||||
@@ -588,24 +597,29 @@ GEM
|
||||
roo (2.7.1)
|
||||
nokogiri (~> 1)
|
||||
rubyzip (~> 1.1, < 2.0.0)
|
||||
rspec (2.14.1)
|
||||
rspec-core (~> 2.14.0)
|
||||
rspec-expectations (~> 2.14.0)
|
||||
rspec-mocks (~> 2.14.0)
|
||||
rspec-core (2.14.4)
|
||||
rspec-expectations (2.14.0)
|
||||
diff-lcs (>= 1.1.3, < 2.0)
|
||||
rspec-mocks (2.14.2)
|
||||
rspec-rails (2.14.2)
|
||||
rspec (3.7.0)
|
||||
rspec-core (~> 3.7.0)
|
||||
rspec-expectations (~> 3.7.0)
|
||||
rspec-mocks (~> 3.7.0)
|
||||
rspec-core (3.7.0)
|
||||
rspec-support (~> 3.7.0)
|
||||
rspec-expectations (3.7.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.7.0)
|
||||
rspec-mocks (3.7.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.7.0)
|
||||
rspec-rails (3.7.2)
|
||||
actionpack (>= 3.0)
|
||||
activemodel (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
railties (>= 3.0)
|
||||
rspec-core (~> 2.14.0)
|
||||
rspec-expectations (~> 2.14.0)
|
||||
rspec-mocks (~> 2.14.0)
|
||||
rspec-retry (0.4.2)
|
||||
rspec-core
|
||||
rspec-core (~> 3.7.0)
|
||||
rspec-expectations (~> 3.7.0)
|
||||
rspec-mocks (~> 3.7.0)
|
||||
rspec-support (~> 3.7.0)
|
||||
rspec-retry (0.5.6)
|
||||
rspec-core (> 3.3, < 3.8)
|
||||
rspec-support (3.7.0)
|
||||
rubocop (0.49.1)
|
||||
parallel (~> 1.10)
|
||||
parser (>= 2.3.3.1, < 3.0)
|
||||
@@ -623,7 +637,10 @@ GEM
|
||||
tilt (~> 1.3)
|
||||
select2-rails (3.5.10)
|
||||
thor (~> 0.14)
|
||||
shoulda-matchers (1.1.0)
|
||||
shellany (0.0.1)
|
||||
shoulda-matchers (2.8.0)
|
||||
activesupport (>= 3.0.0)
|
||||
skylight (1.5.0)
|
||||
activesupport (>= 3.0.0)
|
||||
spinjs-rails (1.3)
|
||||
rails (>= 3.1)
|
||||
@@ -639,10 +656,9 @@ GEM
|
||||
therubyracer (0.12.0)
|
||||
libv8 (~> 3.16.14.0)
|
||||
ref
|
||||
thor (0.19.4)
|
||||
thor (0.20.0)
|
||||
tilt (1.4.1)
|
||||
timecop (0.8.1)
|
||||
timers (1.1.0)
|
||||
timecop (0.9.1)
|
||||
treetop (1.4.15)
|
||||
polyglot
|
||||
polyglot (>= 0.3.1)
|
||||
@@ -650,8 +666,6 @@ GEM
|
||||
turbo-sprockets-rails3 (0.3.6)
|
||||
railties (> 3.2.8, < 4.0.0)
|
||||
sprockets (>= 2.0.0)
|
||||
turn (0.8.3)
|
||||
ansi
|
||||
tzinfo (0.3.53)
|
||||
uglifier (2.7.1)
|
||||
execjs (>= 0.3.0)
|
||||
@@ -669,12 +683,12 @@ GEM
|
||||
actionpack (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
railties (>= 3.0)
|
||||
warden (1.2.6)
|
||||
warden (1.2.7)
|
||||
rack (>= 1.0)
|
||||
webmock (1.8.11)
|
||||
addressable (>= 2.2.7)
|
||||
crack (>= 0.1.7)
|
||||
websocket-driver (0.6.3)
|
||||
websocket-driver (0.7.0)
|
||||
websocket-extensions (>= 0.1.0)
|
||||
websocket-extensions (0.1.2)
|
||||
whenever (0.9.2)
|
||||
@@ -683,7 +697,7 @@ GEM
|
||||
wicked_pdf (1.1.0)
|
||||
wkhtmltopdf-binary (0.12.3.1)
|
||||
xml-simple (1.1.5)
|
||||
xpath (2.0.0)
|
||||
xpath (2.1.0)
|
||||
nokogiri (~> 1.3)
|
||||
|
||||
PLATFORMS
|
||||
@@ -703,7 +717,7 @@ DEPENDENCIES
|
||||
blockenspiel
|
||||
bugsnag
|
||||
byebug (~> 9.0.0)
|
||||
capybara
|
||||
capybara (>= 2.15.4)
|
||||
coffee-rails (~> 3.2.1)
|
||||
compass-rails
|
||||
css_splitter
|
||||
@@ -723,23 +737,24 @@ DEPENDENCIES
|
||||
foundation-icons-sass-rails
|
||||
foundation-rails
|
||||
foundation_rails_helper!
|
||||
fuubar
|
||||
fuubar (~> 2.2.0)
|
||||
geocoder
|
||||
gmaps4rails
|
||||
guard
|
||||
guard-livereload
|
||||
guard-rails
|
||||
guard-rspec
|
||||
guard-rspec (~> 4.7.3)
|
||||
haml
|
||||
i18n (~> 0.6.11)
|
||||
i18n-js (~> 3.0.0)
|
||||
immigrant
|
||||
jquery-migrate-rails
|
||||
jquery-rails
|
||||
json_spec
|
||||
json_spec (~> 1.1.4)
|
||||
jwt (~> 1.5)
|
||||
knapsack
|
||||
letter_opener
|
||||
letter_opener (>= 1.4.1)
|
||||
listen (= 3.0.8)
|
||||
momentjs-rails
|
||||
newrelic_rpm
|
||||
nokogiri (>= 1.6.7.1)
|
||||
@@ -750,7 +765,7 @@ DEPENDENCIES
|
||||
paperclip
|
||||
parallel_tests
|
||||
pg
|
||||
poltergeist
|
||||
poltergeist (>= 1.16.0)
|
||||
pry-byebug (>= 3.4.3)
|
||||
rabl
|
||||
rack-livereload
|
||||
@@ -761,13 +776,14 @@ DEPENDENCIES
|
||||
representative_view
|
||||
roadie-rails (~> 1.0.3)
|
||||
roo (~> 2.7.0)
|
||||
rspec-rails
|
||||
rspec-rails (>= 3.5.2)
|
||||
rspec-retry
|
||||
rubocop (>= 0.49.1)
|
||||
sass (~> 3.3)
|
||||
sass-rails (~> 3.2.3)
|
||||
shoulda-matchers
|
||||
simple_form!
|
||||
skylight (< 2.0)
|
||||
spinjs-rails
|
||||
spree!
|
||||
spree_auth_devise!
|
||||
@@ -778,7 +794,6 @@ DEPENDENCIES
|
||||
timecop
|
||||
truncate_html
|
||||
turbo-sprockets-rails3
|
||||
turn (~> 0.8.3)
|
||||
uglifier (>= 1.0.3)
|
||||
unicorn
|
||||
unicorn-rails
|
||||
@@ -791,4 +806,4 @@ RUBY VERSION
|
||||
ruby 2.1.5p273
|
||||
|
||||
BUNDLED WITH
|
||||
1.15.4
|
||||
1.16.1
|
||||
|
||||
36
README.md
36
README.md
@@ -45,41 +45,15 @@ You can download the source with the command:
|
||||
|
||||
### Get it running
|
||||
|
||||
For those new to Rails, the following tutorial will help get you up to speed with configuring a Rails environment: http://guides.rubyonrails.org/getting_started.html .
|
||||
For those new to Rails, the following tutorial will help get you up to speed with configuring a [Rails environment](http://guides.rubyonrails.org/getting_started.html).
|
||||
|
||||
First, check your dependencies: Ensure that you have Ruby 2.1.5 installed:
|
||||
When ready, run `script/setup`. If the script succeeds you're ready to start developing. If not, take a look at the output as it should be informative enough to help you troubleshoot.
|
||||
|
||||
ruby --version
|
||||
If you run into any other issues getting your local environment up and running please consult [the wiki](https://github.com/openfoodfoundation/openfoodnetwork/wiki).
|
||||
|
||||
Install the project's gem dependencies:
|
||||
If still you get stuck do not hesitate to open an issue reporting the full output of the script.
|
||||
|
||||
cd openfoodnetwork
|
||||
./script/upgrade_bundler.sh
|
||||
bundle install
|
||||
|
||||
Configure the site:
|
||||
|
||||
cp config/application.yml.example config/application.yml
|
||||
edit config/application.yml
|
||||
|
||||
Create a PostgreSQL user:
|
||||
|
||||
* Login as your system postrgresql priviledged user: `sudo -i -u postgres` (this may vary on your OS). Now your prompt looks like: `[postgres@your_host ~]$`
|
||||
* Create the `ofn` database superuser and give it the password `f00d`:
|
||||
|
||||
```
|
||||
createuser -s -P ofn
|
||||
```
|
||||
|
||||
Create the development and test databases, using the settings specified in `config/database.yml`, and populate them with a schema and seed data:
|
||||
```
|
||||
bundle exec rake db:setup
|
||||
```
|
||||
Load some default data for your environment:
|
||||
```
|
||||
bundle exec rake openfoodnetwork:dev:load_sample_data
|
||||
```
|
||||
At long last, your dreams of spinning up a development server can be realised:
|
||||
Now, your dreams of spinning up a development server can be realised:
|
||||
```
|
||||
bundle exec rails server
|
||||
```
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
//= require admin/spree_paypal_express
|
||||
//= require ../shared/ng-infinite-scroll.min.js
|
||||
//= require ../shared/ng-tags-input.min.js
|
||||
//= require moment
|
||||
//= require angular-rails-templates
|
||||
//= require_tree ../templates/admin
|
||||
//= require ./admin_ofn
|
||||
@@ -39,6 +40,7 @@
|
||||
//= require ./resources/resources
|
||||
//= require ./shipping_methods/shipping_methods
|
||||
//= require ./side_menu/side_menu
|
||||
//= require ./subscriptions/subscriptions
|
||||
//= require ./tag_rules/tag_rules
|
||||
//= require ./taxons/taxons
|
||||
//= require ./utils/utils
|
||||
@@ -49,6 +51,14 @@
|
||||
//= require textAngular.min.js
|
||||
//= require i18n/translations
|
||||
//= require darkswarm/i18n.translate.js
|
||||
|
||||
//
|
||||
//= require moment
|
||||
//= require moment/en-gb.js
|
||||
//= require moment/es.js
|
||||
//= require moment/fr.js
|
||||
//= require moment/it.js
|
||||
//= require moment/nb.js
|
||||
//= require moment/pt-br.js
|
||||
//= require moment/sv.js
|
||||
|
||||
//= require_tree .
|
||||
|
||||
@@ -32,7 +32,6 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
$scope.filteredProducts = []
|
||||
$scope.currentFilters = []
|
||||
$scope.limit = 15
|
||||
$scope.productsWithUnsavedVariants = []
|
||||
$scope.query = ""
|
||||
$scope.DisplayProperties = DisplayProperties
|
||||
|
||||
@@ -114,7 +113,6 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
display_name: null
|
||||
on_hand: null
|
||||
price: null
|
||||
$scope.productsWithUnsavedVariants.push product
|
||||
DisplayProperties.setShowVariants product.id, true
|
||||
|
||||
|
||||
@@ -196,7 +194,7 @@ angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout
|
||||
filters: $scope.currentFilters
|
||||
).success((data) ->
|
||||
DirtyProducts.clear()
|
||||
BulkProducts.updateVariantLists(data.products, $scope.productsWithUnsavedVariants)
|
||||
BulkProducts.updateVariantLists(data.products || [])
|
||||
$timeout -> $scope.displaySuccess()
|
||||
).error (data, status) ->
|
||||
if status == 400 && data.errors? && data.errors.length > 0
|
||||
|
||||
@@ -2,6 +2,7 @@ angular.module("admin.customers").directive 'editAddressDialog', ($compile, $tem
|
||||
restrict: 'A'
|
||||
scope: true
|
||||
link: (scope, element, attr) ->
|
||||
template = null
|
||||
scope.errors = []
|
||||
|
||||
scope.$watch 'address.country_id', (newVal) ->
|
||||
@@ -18,19 +19,19 @@ angular.module("admin.customers").directive 'editAddressDialog', ($compile, $tem
|
||||
else
|
||||
scope.errors.push(t('admin.customers.index.update_address_error'))
|
||||
|
||||
|
||||
template = $compile($templateCache.get('admin/edit_address_dialog.html'))(scope)
|
||||
template.dialog(DialogDefaults)
|
||||
|
||||
element.bind 'click', (e) ->
|
||||
if e.target.id == 'bill-address-link'
|
||||
scope.addressType = 'bill_address'
|
||||
else
|
||||
scope.addressType = 'ship_address'
|
||||
scope.address = scope.customer[scope.addressType]
|
||||
scope.states = scope.filter_states(scope.address?.country_id)
|
||||
|
||||
template = $compile($templateCache.get('admin/edit_address_dialog.html'))(scope)
|
||||
template.dialog(DialogDefaults)
|
||||
template.dialog('open')
|
||||
scope.$apply()
|
||||
|
||||
scope.filter_states = (countryID) ->
|
||||
$filter('filter')(scope.availableCountries, {id: countryID})[0].states
|
||||
return [] unless countryID
|
||||
$filter('filter')(scope.availableCountries, {id: parseInt(countryID)}, true)[0].states
|
||||
@@ -12,7 +12,10 @@ angular.module("admin.customers").directive 'newCustomerDialog', ($compile, $tem
|
||||
scope.submitted = true
|
||||
scope.errors = []
|
||||
if scope.new_customer_form.$valid
|
||||
Customers.add(scope.email).$promise.then (data) ->
|
||||
params =
|
||||
enterprise_id: CurrentShop.shop.id
|
||||
email: scope.email
|
||||
Customers.add(params).$promise.then (data) ->
|
||||
if data.id
|
||||
scope.email = ""
|
||||
scope.submitted = false
|
||||
|
||||
@@ -8,4 +8,4 @@ angular.module("ofn.admin").directive "datetimepicker", ->
|
||||
onSelect: (dateText, inst) ->
|
||||
scope.$apply (scope) ->
|
||||
# Fires ngModel.$parsers
|
||||
ngModel.$setViewValue dateText
|
||||
ngModel.$setViewValue dateText
|
||||
|
||||
@@ -1 +1 @@
|
||||
angular.module("admin.dropdown", ['templates'])
|
||||
angular.module("admin.dropdown", ['admin.utils'])
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
angular.module("admin.enterpriseRoles", [])
|
||||
@@ -4,10 +4,8 @@ angular.module("admin.enterprises")
|
||||
$scope.PaymentMethods = EnterprisePaymentMethods.paymentMethods
|
||||
$scope.ShippingMethods = EnterpriseShippingMethods.shippingMethods
|
||||
$scope.navClear = NavigationCheck.clear
|
||||
$scope.pristineEmail = $scope.Enterprise.email
|
||||
$scope.menu = SideMenu
|
||||
$scope.newManager = { id: '', email: (t('add_manager')) }
|
||||
|
||||
$scope.StatusMessage = StatusMessage
|
||||
|
||||
$scope.$watch 'enterprise_form.$dirty', (newValue) ->
|
||||
@@ -36,6 +34,8 @@ angular.module("admin.enterprises")
|
||||
|
||||
$scope.removeManager = (manager) ->
|
||||
if manager.id?
|
||||
if manager.id == $scope.Enterprise.owner.id or manager.id == parseInt($scope.receivesNotifications)
|
||||
return
|
||||
for i, user of $scope.Enterprise.users when user.id == manager.id
|
||||
$scope.Enterprise.users.splice i, 1
|
||||
if $scope.enterprise_form?
|
||||
@@ -46,6 +46,7 @@ angular.module("admin.enterprises")
|
||||
manager =
|
||||
id: manager.id
|
||||
email: manager.email
|
||||
confirmed: manager.confirmed
|
||||
if (user for user in $scope.Enterprise.users when user.id == manager.id).length == 0
|
||||
$scope.Enterprise.users.push manager
|
||||
else
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
angular.module('admin.enterprises').directive 'enterpriseLimit', (InfoDialog) ->
|
||||
restrict: 'A'
|
||||
scope: {
|
||||
limit_reached: '=enterpriseLimit',
|
||||
modal_message: '@modalMessage'
|
||||
}
|
||||
link: (scope, element, attr) ->
|
||||
element.bind 'click', (event)->
|
||||
if scope.limit_reached
|
||||
event.preventDefault()
|
||||
InfoDialog.open 'error', scope.modal_message
|
||||
@@ -1,7 +1,7 @@
|
||||
angular.module("admin.enterprises")
|
||||
.factory "EnterprisePaymentMethods", (enterprise, PaymentMethods) ->
|
||||
new class EnterprisePaymentMethods
|
||||
paymentMethods: PaymentMethods.paymentMethods
|
||||
paymentMethods: PaymentMethods.all
|
||||
|
||||
constructor: ->
|
||||
for payment_method in @paymentMethods
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
angular.module("admin.enterprises")
|
||||
.factory "EnterpriseShippingMethods", (enterprise, ShippingMethods) ->
|
||||
new class EnterpriseShippingMethods
|
||||
shippingMethods: ShippingMethods.shippingMethods
|
||||
shippingMethods: ShippingMethods.all
|
||||
|
||||
constructor: ->
|
||||
for shipping_method in @shippingMethods
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
angular.module("admin.indexUtils").directive "datepicker", ->
|
||||
require: "ngModel"
|
||||
link: (scope, element, attrs, ngModel) ->
|
||||
element.datepicker
|
||||
dateFormat: "yy-mm-dd"
|
||||
onSelect: (dateText, inst) ->
|
||||
scope.$apply (scope) ->
|
||||
# Fires ngModel.$parsers
|
||||
ngModel.$setViewValue dateText
|
||||
@@ -1 +1,2 @@
|
||||
angular.module("admin.indexUtils", ['admin.resources', 'ngSanitize', 'templates', 'admin.utils']).config ($httpProvider) ->
|
||||
angular.module("admin.indexUtils", ['admin.resources', 'ngSanitize', 'templates', 'admin.utils']).config ($httpProvider) ->
|
||||
$httpProvider.defaults.headers.common["X-CSRF-Token"] = $("meta[name=csrf-token]").attr("content");
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
angular.module("admin.indexUtils").factory 'Panels', ->
|
||||
new class Panels
|
||||
panels: []
|
||||
all: []
|
||||
|
||||
register: (ctrl, object, selected=null) ->
|
||||
if ctrl? && object?
|
||||
@panels.push { ctrl: ctrl, object: object, selected: selected }
|
||||
existing = @panelFor(object)
|
||||
newPanel = { ctrl: ctrl, object: object, selected: selected }
|
||||
if existing then angular.extend(existing, newPanel) else @all.push(newPanel)
|
||||
ctrl.select(selected) if selected?
|
||||
|
||||
toggle: (object, name, state=null) ->
|
||||
panel = @findPanelByObject(object)
|
||||
panel = @panelFor(object)
|
||||
if panel.selected == name
|
||||
@select(panel, null) unless state == "open"
|
||||
else
|
||||
@@ -18,5 +20,5 @@ angular.module("admin.indexUtils").factory 'Panels', ->
|
||||
panel.selected = name
|
||||
panel.ctrl.select(name)
|
||||
|
||||
findPanelByObject: (object) ->
|
||||
(panel for panel in @panels when panel.object == object)[0]
|
||||
panelFor: (object) ->
|
||||
(@all.filter (panel) -> panel.object == object)[0]
|
||||
|
||||
@@ -6,7 +6,7 @@ angular.module("admin.indexUtils").factory "pendingChanges", ($q, resources, Sta
|
||||
add: (id, attr, change) =>
|
||||
@pendingChanges["#{id}"] = {} unless @pendingChanges.hasOwnProperty("#{id}")
|
||||
@pendingChanges["#{id}"]["#{attr}"] = change
|
||||
StatusMessage.display('notice', "You have made #{@changeCount(@pendingChanges)} unsaved changes")
|
||||
StatusMessage.display('notice', t('admin.unsaved_changes'))
|
||||
|
||||
removeAll: =>
|
||||
@pendingChanges = {}
|
||||
|
||||
@@ -3,8 +3,8 @@ angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout,
|
||||
$scope.RequestMonitor = RequestMonitor
|
||||
$scope.filteredLineItems = []
|
||||
$scope.confirmDelete = true
|
||||
$scope.startDate = formatDate daysFromToday -7
|
||||
$scope.endDate = formatDate daysFromToday 1
|
||||
$scope.startDate = moment().startOf('day').subtract(7, 'days').format('YYYY-MM-DD')
|
||||
$scope.endDate = moment().startOf('day').format('YYYY-MM-DD')
|
||||
$scope.bulkActions = [ { name: t("admin.orders.bulk_management.actions_delete"), callback: 'deleteLineItems' } ]
|
||||
$scope.selectedUnitsProduct = {}
|
||||
$scope.selectedUnitsVariant = {}
|
||||
@@ -22,16 +22,16 @@ angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout,
|
||||
|
||||
$scope.refreshData = ->
|
||||
unless !$scope.orderCycleFilter? || $scope.orderCycleFilter == 0
|
||||
$scope.startDate = OrderCycles.byID[$scope.orderCycleFilter].first_order
|
||||
$scope.endDate = OrderCycles.byID[$scope.orderCycleFilter].last_order
|
||||
$scope.startDate = moment(OrderCycles.byID[$scope.orderCycleFilter].orders_open_at).format('YYYY-MM-DD')
|
||||
$scope.endDate = moment(OrderCycles.byID[$scope.orderCycleFilter].orders_close_at).startOf('day').format('YYYY-MM-DD')
|
||||
|
||||
RequestMonitor.load $scope.orders = Orders.index("q[state_not_eq]": "canceled", "q[completed_at_not_null]": "true", "q[completed_at_gt]": "#{parseDate($scope.startDate)}", "q[completed_at_lt]": "#{parseDate($scope.endDate)}")
|
||||
RequestMonitor.load $scope.lineItems = LineItems.index("q[order][state_not_eq]": "canceled", "q[order][completed_at_not_null]": "true", "q[order][completed_at_gt]": "#{parseDate($scope.startDate)}", "q[order][completed_at_lt]": "#{parseDate($scope.endDate)}")
|
||||
RequestMonitor.load $scope.orders = Orders.index("q[state_not_eq]": "canceled", "q[completed_at_not_null]": "true", "q[completed_at_gteq]": "#{moment($scope.startDate).format()}", "q[completed_at_lt]": "#{moment($scope.endDate).add(1,'day').format()}")
|
||||
RequestMonitor.load $scope.lineItems = LineItems.index("q[order][state_not_eq]": "canceled", "q[order][completed_at_not_null]": "true", "q[order][completed_at_gteq]": "#{moment($scope.startDate).format()}", "q[order][completed_at_lt]": "#{moment($scope.endDate).add(1,'day').format()}")
|
||||
|
||||
unless $scope.initialized
|
||||
RequestMonitor.load $scope.distributors = Enterprises.index(action: "for_line_items", ams_prefix: "basic", "q[sells_in][]": ["own", "any"])
|
||||
RequestMonitor.load $scope.orderCycles = OrderCycles.index(ams_prefix: "basic", as: "distributor", "q[orders_close_at_gt]": "#{daysFromToday(-90)}")
|
||||
RequestMonitor.load $scope.suppliers = Enterprises.index(action: "for_line_items", ams_prefix: "basic", "q[is_primary_producer_eq]": "true")
|
||||
RequestMonitor.load $scope.distributors = Enterprises.index(action: "visible", ams_prefix: "basic", "q[sells_in][]": ["own", "any"])
|
||||
RequestMonitor.load $scope.orderCycles = OrderCycles.index(ams_prefix: "basic", as: "distributor", "q[orders_close_at_gt]": "#{moment().subtract(90,'days').format()}")
|
||||
RequestMonitor.load $scope.suppliers = Enterprises.index(action: "visible", ams_prefix: "basic", "q[is_primary_producer_eq]": "true")
|
||||
|
||||
RequestMonitor.load $q.all([$scope.orders.$promise, $scope.distributors.$promise, $scope.orderCycles.$promise]).then ->
|
||||
Dereferencer.dereferenceAttr $scope.orders, "distributor", Enterprises.byID
|
||||
@@ -142,31 +142,3 @@ angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout,
|
||||
if lineItem.quantity > 0
|
||||
lineItem.final_weight_volume = LineItems.pristineByID[lineItem.id].final_weight_volume * lineItem.quantity / LineItems.pristineByID[lineItem.id].quantity
|
||||
$scope.weightAdjustedPrice(lineItem)
|
||||
|
||||
daysFromToday = (days) ->
|
||||
now = new Date
|
||||
now.setHours(0)
|
||||
now.setMinutes(0)
|
||||
now.setSeconds(0)
|
||||
now.setDate( now.getDate() + days )
|
||||
now
|
||||
|
||||
formatDate = (date) ->
|
||||
year = date.getFullYear()
|
||||
month = twoDigitNumber date.getMonth() + 1
|
||||
day = twoDigitNumber date.getDate()
|
||||
return year + "-" + month + "-" + day
|
||||
|
||||
formatTime = (date) ->
|
||||
hours = twoDigitNumber date.getHours()
|
||||
mins = twoDigitNumber date.getMinutes()
|
||||
secs = twoDigitNumber date.getSeconds()
|
||||
return hours + ":" + mins + ":" + secs
|
||||
|
||||
parseDate = (dateString) ->
|
||||
new Date(Date.parse(dateString))
|
||||
|
||||
twoDigitNumber = (number) ->
|
||||
twoDigits = "" + number
|
||||
twoDigits = ("0" + number) if number < 10
|
||||
twoDigits
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
angular.module('admin.orderCycles')
|
||||
.controller 'AdminCreateOrderCycleCtrl', ($scope, $filter, $window, OrderCycle, Enterprise, EnterpriseFee, ocInstance, StatusMessage) ->
|
||||
.controller 'AdminCreateOrderCycleCtrl', ($scope, $filter, $window, OrderCycle, Enterprise, EnterpriseFee, Schedules, RequestMonitor, ocInstance, StatusMessage) ->
|
||||
$scope.enterprises = Enterprise.index(coordinator_id: ocInstance.coordinator_id)
|
||||
$scope.supplier_enterprises = Enterprise.producer_enterprises
|
||||
$scope.distributor_enterprises = Enterprise.hub_enterprises
|
||||
$scope.supplied_products = Enterprise.supplied_products
|
||||
$scope.enterprise_fees = EnterpriseFee.index(coordinator_id: ocInstance.coordinator_id)
|
||||
$scope.schedules = Schedules.index()
|
||||
|
||||
$scope.OrderCycle = OrderCycle
|
||||
$scope.order_cycle = OrderCycle.new({ coordinator_id: ocInstance.coordinator_id})
|
||||
@@ -18,7 +19,7 @@ angular.module('admin.orderCycles')
|
||||
StatusMessage.setValidation(isValid)
|
||||
|
||||
$scope.loaded = ->
|
||||
Enterprise.loaded && EnterpriseFee.loaded && OrderCycle.loaded
|
||||
Enterprise.loaded && EnterpriseFee.loaded && OrderCycle.loaded && !RequestMonitor.loading
|
||||
|
||||
$scope.suppliedVariants = (enterprise_id) ->
|
||||
Enterprise.suppliedVariants(enterprise_id)
|
||||
@@ -89,4 +90,3 @@ angular.module('admin.orderCycles')
|
||||
|
||||
$scope.cancel = (destination) ->
|
||||
$window.location = destination
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
angular.module('admin.orderCycles')
|
||||
.controller 'AdminEditOrderCycleCtrl', ($scope, $filter, $location, $window, OrderCycle, Enterprise, EnterpriseFee, StatusMessage) ->
|
||||
.controller 'AdminEditOrderCycleCtrl', ($scope, $filter, $location, $window, OrderCycle, Enterprise, EnterpriseFee, StatusMessage, Schedules, RequestMonitor) ->
|
||||
order_cycle_id = $location.absUrl().match(/\/admin\/order_cycles\/(\d+)/)[1]
|
||||
$scope.enterprises = Enterprise.index(order_cycle_id: order_cycle_id)
|
||||
$scope.supplier_enterprises = Enterprise.producer_enterprises
|
||||
$scope.distributor_enterprises = Enterprise.hub_enterprises
|
||||
$scope.supplied_products = Enterprise.supplied_products
|
||||
$scope.enterprise_fees = EnterpriseFee.index(order_cycle_id: order_cycle_id)
|
||||
$scope.schedules = Schedules.index()
|
||||
|
||||
$scope.OrderCycle = OrderCycle
|
||||
$scope.order_cycle = OrderCycle.load(order_cycle_id)
|
||||
@@ -19,7 +20,7 @@ angular.module('admin.orderCycles')
|
||||
StatusMessage.setValidation(isValid)
|
||||
|
||||
$scope.loaded = ->
|
||||
Enterprise.loaded && EnterpriseFee.loaded && OrderCycle.loaded
|
||||
Enterprise.loaded && EnterpriseFee.loaded && OrderCycle.loaded && !RequestMonitor.loading
|
||||
|
||||
$scope.suppliedVariants = (enterprise_id) ->
|
||||
Enterprise.suppliedVariants(enterprise_id)
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
angular.module("admin.orderCycles").controller "OrderCyclesCtrl", ($scope, $q, Columns, StatusMessage, RequestMonitor, OrderCycles, Enterprises, Schedules, Dereferencer) ->
|
||||
$scope.RequestMonitor = RequestMonitor
|
||||
$scope.columns = Columns.columns
|
||||
$scope.saveAll = -> OrderCycles.saveChanges($scope.order_cycles_form)
|
||||
$scope.ordersCloseAtLimit = -31 # days
|
||||
$scope.involvingFilter = 0
|
||||
$scope.scheduleFilter = 0
|
||||
|
||||
compileData = ->
|
||||
for schedule in $scope.schedules
|
||||
Dereferencer.dereference(schedule.order_cycles, OrderCycles.byID)
|
||||
for orderCycle in $scope.orderCycles
|
||||
coordinator = Enterprises.byID[orderCycle.coordinator.id]
|
||||
orderCycle.coordinator = coordinator if coordinator?
|
||||
Dereferencer.dereference(orderCycle.producers, Enterprises.byID)
|
||||
Dereferencer.dereference(orderCycle.shops, Enterprises.byID)
|
||||
Dereferencer.dereference(orderCycle.schedules, Schedules.byID)
|
||||
orderCycle.involvedEnterpriseIDs = [orderCycle.coordinator.id]
|
||||
orderCycle.producerNames = orderCycle.producers.map((producer) -> orderCycle.involvedEnterpriseIDs.push(producer.id); producer.name).join(", ")
|
||||
orderCycle.shopNames = orderCycle.shops.map((shop) -> orderCycle.involvedEnterpriseIDs.push(shop.id); shop.name).join(", ")
|
||||
|
||||
# NOTE: this is using the Enterprises service from the admin.enterprises module
|
||||
RequestMonitor.load ($scope.enterprises = Enterprises.index(action: "visible", ams_prefix: "basic")).$promise
|
||||
$scope.schedules = Schedules.index()
|
||||
$scope.orderCycles = OrderCycles.index(ams_prefix: "index", "q[orders_close_at_gt]": "#{daysFromToday($scope.ordersCloseAtLimit)}")
|
||||
RequestMonitor.load $q.all([$scope.enterprises.$promise, $scope.schedules.$promise, $scope.orderCycles.$promise]).then -> compileData()
|
||||
|
||||
$scope.$watch 'order_cycles_form.$dirty', (newVal, oldVal) ->
|
||||
StatusMessage.display 'notice', "You have unsaved changes" if newVal
|
||||
|
||||
$scope.showMore = (days) ->
|
||||
$scope.ordersCloseAtLimit -= days
|
||||
existingIDs = Object.keys(OrderCycles.byID)
|
||||
orderCycles = OrderCycles.index(ams_prefix: "index", "q[orders_close_at_gt]": "#{daysFromToday($scope.ordersCloseAtLimit)}", "q[id_not_in][]": existingIDs)
|
||||
orderCycles.$promise.then ->
|
||||
$scope.orderCycles.push(orderCycle) for orderCycle in orderCycles
|
||||
compileData()
|
||||
|
||||
daysFromToday = (days) ->
|
||||
now = new Date
|
||||
now.setHours(0)
|
||||
now.setMinutes(0)
|
||||
now.setSeconds(0)
|
||||
now.setDate( now.getDate() + days )
|
||||
now
|
||||
@@ -1,6 +1,7 @@
|
||||
angular.module('admin.orderCycles').controller "AdminSimpleCreateOrderCycleCtrl", ($scope, $window, OrderCycle, Enterprise, EnterpriseFee, StatusMessage, ocInstance) ->
|
||||
angular.module('admin.orderCycles').controller "AdminSimpleCreateOrderCycleCtrl", ($scope, $window, OrderCycle, Enterprise, EnterpriseFee, StatusMessage, Schedules, RequestMonitor, ocInstance) ->
|
||||
$scope.StatusMessage = StatusMessage
|
||||
$scope.OrderCycle = OrderCycle
|
||||
$scope.schedules = Schedules.index()
|
||||
$scope.order_cycle = OrderCycle.new {coordinator_id: ocInstance.coordinator_id}, =>
|
||||
# TODO: make this a get method, which only fetches one enterprise
|
||||
$scope.enterprises = Enterprise.index {coordinator_id: ocInstance.coordinator_id}, (enterprises) =>
|
||||
@@ -26,7 +27,7 @@ angular.module('admin.orderCycles').controller "AdminSimpleCreateOrderCycleCtrl"
|
||||
OrderCycle.order_cycle.coordinator_id = enterprise.id
|
||||
|
||||
$scope.loaded = ->
|
||||
Enterprise.loaded && EnterpriseFee.loaded && OrderCycle.loaded
|
||||
Enterprise.loaded && EnterpriseFee.loaded && OrderCycle.loaded && !RequestMonitor.loading
|
||||
|
||||
$scope.removeDistributionOfVariant = angular.noop
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
angular.module('admin.orderCycles').controller "AdminSimpleEditOrderCycleCtrl", ($scope, $location, $window, OrderCycle, Enterprise, EnterpriseFee, StatusMessage) ->
|
||||
angular.module('admin.orderCycles').controller "AdminSimpleEditOrderCycleCtrl", ($scope, $location, $window, OrderCycle, Enterprise, EnterpriseFee, Schedules, RequestMonitor, StatusMessage) ->
|
||||
$scope.orderCycleId = ->
|
||||
$location.absUrl().match(/\/admin\/order_cycles\/(\d+)/)[1]
|
||||
|
||||
$scope.StatusMessage = StatusMessage
|
||||
$scope.enterprises = Enterprise.index(order_cycle_id: $scope.orderCycleId())
|
||||
$scope.enterprise_fees = EnterpriseFee.index(order_cycle_id: $scope.orderCycleId())
|
||||
$scope.schedules = Schedules.index()
|
||||
$scope.OrderCycle = OrderCycle
|
||||
$scope.order_cycle = OrderCycle.load $scope.orderCycleId(), (order_cycle) =>
|
||||
$scope.init()
|
||||
@@ -16,7 +17,7 @@ angular.module('admin.orderCycles').controller "AdminSimpleEditOrderCycleCtrl",
|
||||
StatusMessage.setValidation(isValid)
|
||||
|
||||
$scope.loaded = ->
|
||||
Enterprise.loaded && EnterpriseFee.loaded && OrderCycle.loaded
|
||||
Enterprise.loaded && EnterpriseFee.loaded && OrderCycle.loaded && !RequestMonitor.loading
|
||||
|
||||
$scope.init = ->
|
||||
$scope.outgoing_exchange = OrderCycle.order_cycle.outgoing_exchanges[0]
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
angular.module("admin.orderCycles").directive 'orderCyclesSelector', ($timeout, OrderCycles) ->
|
||||
restrict: 'C'
|
||||
templateUrl: 'admin/order_cycles_selector.html'
|
||||
link: (scope, element, attr) ->
|
||||
scope.orderCycles = OrderCycles.all.filter (oc) -> oc.viewing_as_coordinator
|
||||
|
||||
$timeout ->
|
||||
scope.selections =
|
||||
available: scope.availableOrderCycles[0]
|
||||
selected: scope.selectedOrderCycles[0]
|
||||
|
||||
scope.add = (orderCycle) ->
|
||||
orderCycle ?= scope.selections.available
|
||||
index = scope.availableOrderCycles.indexOf(orderCycle)
|
||||
if index > -1
|
||||
scope.selectedOrderCycles.push orderCycle
|
||||
scope.selections.available = scope.availableOrderCycles[index+1] || scope.availableOrderCycles[index-1]
|
||||
scope.selections.selected = orderCycle
|
||||
|
||||
scope.remove = (orderCycle) ->
|
||||
orderCycle ?= scope.selections.selected
|
||||
index = scope.selectedOrderCycles.indexOf(orderCycle)
|
||||
if index > -1
|
||||
scope.selectedOrderCycles.splice(index, 1)
|
||||
scope.selections.selected = scope.selectedOrderCycles[index] || scope.selectedOrderCycles[index-1]
|
||||
scope.selections.available = orderCycle
|
||||
@@ -0,0 +1,56 @@
|
||||
angular.module("admin.orderCycles").directive 'scheduleDialog', ($window, $compile, $injector, $templateCache, DialogDefaults, OrderCycles, Schedules) ->
|
||||
restrict: 'A'
|
||||
scope:
|
||||
scheduleId: '@'
|
||||
showMore: '&'
|
||||
link: (scope, element, attr) ->
|
||||
# Link opening of dialog to click event on element
|
||||
element.bind 'click', (e) ->
|
||||
existing = Schedules.byID[scope.scheduleId]
|
||||
scope.schedule =
|
||||
id: existing?.id
|
||||
name: existing?.name || ''
|
||||
order_cycle_ids: existing?.order_cycle_ids || []
|
||||
scope.selectedOrderCycles = []
|
||||
scope.selectedOrderCycles.push orderCycle for orderCycle in (existing?.order_cycles || [])
|
||||
scope.submitted = false
|
||||
scope.errors = []
|
||||
# Compile modal template
|
||||
scope.template = $compile($templateCache.get('admin/schedule_dialog.html'))(scope)
|
||||
# Set Dialog options
|
||||
settings = angular.copy(DialogDefaults)
|
||||
scope.template.dialog(angular.extend(settings,{width: $window.innerWidth * 0.6}))
|
||||
scope.template.dialog(close: -> scope.template.remove())
|
||||
scope.template.dialog('open')
|
||||
|
||||
scope.close = ->
|
||||
scope.template.dialog('close')
|
||||
return
|
||||
|
||||
scope.delete = ->
|
||||
if confirm(t('are_you_sure'))
|
||||
Schedules.remove(scope.schedule).$promise.then (data) ->
|
||||
scope.close()
|
||||
|
||||
scope.loadMore = ->
|
||||
scope.showMore().then ->
|
||||
scope.availableOrderCycles = (orderCycle for id, orderCycle of OrderCycles.byID when orderCycle.id not in scope.schedule.order_cycle_ids)
|
||||
|
||||
scope.submit = ->
|
||||
scope.schedule_form.$setPristine()
|
||||
scope.submitted = true
|
||||
scope.errors = []
|
||||
return scope.errors.push(t('admin.order_cycles.index.no_order_cycles_error')) unless scope.selectedOrderCycles.length > 0
|
||||
scope.schedule.order_cycle_ids = scope.selectedOrderCycles.map (oc) -> oc.id
|
||||
if scope.schedule_form.$valid
|
||||
method = if scope.schedule.id? then Schedules.update else Schedules.add
|
||||
method(scope.schedule).$promise.then (data) ->
|
||||
if data.id
|
||||
scope.submitted = false
|
||||
scope.template.dialog('close')
|
||||
, (response) ->
|
||||
if response.data.errors
|
||||
scope.errors.push(error) for error in response.data.errors
|
||||
else
|
||||
scope.errors.push("Sorry! Could not create '#{scope.name}'")
|
||||
return
|
||||
@@ -0,0 +1,15 @@
|
||||
angular.module("admin.orderCycles").directive 'scheduleList', (RequestMonitor, Schedules) ->
|
||||
restrict: 'E'
|
||||
scope:
|
||||
orderCycle: '='
|
||||
template: "<div><span ng-repeat='schedule in schedules'>{{ schedule.name + ($last ? '' : ', ')}}</span></div>"
|
||||
link: (scope, element, attr) ->
|
||||
scope.schedules = []
|
||||
|
||||
scope.$watchCollection 'orderCycle.schedule_ids', (newValue, oldValue) ->
|
||||
return unless newValue? && RequestMonitor.loadId > 0 # Request for schedules needs to have been sent
|
||||
scope.schedules = []
|
||||
RequestMonitor.loadQueue.then ->
|
||||
for id in scope.orderCycle.schedule_ids
|
||||
schedule = Schedules.byID[id]
|
||||
scope.schedules.push schedule if schedule?
|
||||
@@ -0,0 +1,7 @@
|
||||
angular.module("admin.orderCycles").filter "available", ($filter) ->
|
||||
return (orderCycles, selectedOrderCycles) ->
|
||||
return orderCycles unless selectedOrderCycles?.length > 0
|
||||
$filter('filter')(orderCycles, (orderCycle) ->
|
||||
(selectedOrderCycles.indexOf(orderCycle) == -1) &&
|
||||
(orderCycle.coordinator.id == selectedOrderCycles[0].coordinator.id)
|
||||
)
|
||||
@@ -0,0 +1,6 @@
|
||||
angular.module("admin.orderCycles").filter "involving", ($filter) ->
|
||||
return (orderCycles, enterpriseID) ->
|
||||
return orderCycles if enterpriseID == 0
|
||||
$filter('filter')(orderCycles, (orderCycle) ->
|
||||
enterpriseID in orderCycle.involvedEnterpriseIDs
|
||||
)
|
||||
@@ -0,0 +1,6 @@
|
||||
angular.module("admin.orderCycles").filter "schedule", ($filter) ->
|
||||
return (orderCycles, scheduleID) ->
|
||||
return orderCycles if scheduleID == 0
|
||||
$filter('filter')(orderCycles, (orderCycle) ->
|
||||
scheduleID in orderCycle.schedules.map (oc) -> oc.id
|
||||
)
|
||||
@@ -1,32 +0,0 @@
|
||||
angular.module('admin.orderCycles', ['admin.utils', 'admin.indexUtils', 'ngTagsInput'])
|
||||
|
||||
.config ($httpProvider) ->
|
||||
$httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content')
|
||||
|
||||
.directive 'datetimepicker', ($parse) ->
|
||||
(scope, element, attrs) ->
|
||||
# using $parse instead of scope[attrs.datetimepicker] for cases
|
||||
# where attrs.datetimepicker is 'foo.bar.lol'
|
||||
$(element).datetimepicker
|
||||
dateFormat: 'yy-mm-dd'
|
||||
timeFormat: 'HH:mm:ss'
|
||||
showOn: "button"
|
||||
buttonImage: "<%= asset_path 'datepicker/cal.gif' %>"
|
||||
buttonImageOnly: true
|
||||
stepMinute: 15
|
||||
onSelect: (dateText, inst) ->
|
||||
scope.$apply ->
|
||||
parsed = $parse(attrs.datetimepicker)
|
||||
parsed.assign(scope, dateText)
|
||||
|
||||
.directive 'ofnOnChange', ->
|
||||
(scope, element, attrs) ->
|
||||
element.bind 'change', ->
|
||||
scope.$apply(attrs.ofnOnChange)
|
||||
|
||||
.directive 'ofnSyncDistributions', ->
|
||||
(scope, element, attrs) ->
|
||||
element.bind 'change', ->
|
||||
if !$(this).is(':checked')
|
||||
scope.$apply ->
|
||||
scope.removeDistributionOfVariant(attrs.ofnSyncDistributions)
|
||||
@@ -0,0 +1,37 @@
|
||||
angular.module('admin.orderCycles', ['ngTagsInput', 'admin.indexUtils', 'admin.enterprises'])
|
||||
|
||||
.config ($httpProvider) ->
|
||||
$httpProvider.defaults.headers.common['X-CSRF-Token'] = $('meta[name=csrf-token]').attr('content')
|
||||
|
||||
.directive 'datetimepicker', ($timeout, $parse) ->
|
||||
require: "ngModel"
|
||||
link: (scope, element, attrs, ngModel) ->
|
||||
$timeout ->
|
||||
# using $parse instead of scope[attrs.datetimepicker] for cases
|
||||
# where attrs.datetimepicker is 'foo.bar.lol'
|
||||
$(element).datetimepicker
|
||||
dateFormat: 'yy-mm-dd'
|
||||
timeFormat: 'HH:mm:ss'
|
||||
showOn: "button"
|
||||
buttonImage: "<%= asset_path 'datepicker/cal.gif' %>"
|
||||
buttonImageOnly: true
|
||||
stepMinute: 15
|
||||
onSelect: (dateText, inst) ->
|
||||
scope.$apply(->
|
||||
element.val(dateText)
|
||||
parsed = $parse(attrs.datetimepicker)
|
||||
parsed.assign(scope, dateText)
|
||||
)
|
||||
|
||||
|
||||
.directive 'ofnOnChange', ->
|
||||
(scope, element, attrs) ->
|
||||
element.bind 'change', ->
|
||||
scope.$apply(attrs.ofnOnChange)
|
||||
|
||||
.directive 'ofnSyncDistributions', ->
|
||||
(scope, element, attrs) ->
|
||||
element.bind 'change', ->
|
||||
if !$(this).is(':checked')
|
||||
scope.$apply ->
|
||||
scope.removeDistributionOfVariant(attrs.ofnSyncDistributions)
|
||||
@@ -1,5 +1,7 @@
|
||||
angular.module("admin.orders").directive 'customerSearchOverride', ->
|
||||
restrict: 'C'
|
||||
scope:
|
||||
distributorId: '@'
|
||||
link: (scope, element, attr) ->
|
||||
formatCustomerResult = (customer) ->
|
||||
customerTemplate
|
||||
@@ -9,13 +11,14 @@ angular.module("admin.orders").directive 'customerSearchOverride', ->
|
||||
|
||||
element.select2
|
||||
placeholder: Spree.translations.choose_a_customer
|
||||
minimumInputLength: 3
|
||||
ajax:
|
||||
url: '/admin/search/customers.json'
|
||||
datatype: 'json'
|
||||
data: (term, page) ->
|
||||
{
|
||||
q: term
|
||||
distributor_id: $('#distributor_id').val() # modified
|
||||
distributor_id: scope.distributorId # modified
|
||||
}
|
||||
results: (data, page) ->
|
||||
{ results: data }
|
||||
|
||||
@@ -5,4 +5,9 @@ angular.module("admin.resources").factory 'OrderCycleResource', ($resource) ->
|
||||
isArray: true
|
||||
'update':
|
||||
method: 'PUT'
|
||||
'bulkUpdate':
|
||||
method: 'POST'
|
||||
isArray: true
|
||||
params:
|
||||
action: 'bulk_update'
|
||||
})
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
angular.module("admin.resources").factory 'ScheduleResource', ($resource) ->
|
||||
$resource('/admin/schedules/:id/:action.json', {}, {
|
||||
'index':
|
||||
method: 'GET'
|
||||
isArray: true
|
||||
'create':
|
||||
method: 'POST'
|
||||
'update':
|
||||
method: 'PUT'
|
||||
params:
|
||||
id: '@id'
|
||||
'destroy':
|
||||
method: 'DELETE'
|
||||
params:
|
||||
id: '@id'
|
||||
})
|
||||
@@ -1,13 +1,14 @@
|
||||
angular.module("admin.resources").factory "Customers", ($q, InfoDialog, RequestMonitor, CustomerResource, CurrentShop) ->
|
||||
angular.module("admin.resources").factory "Customers", ($q, $injector, InfoDialog, RequestMonitor, CustomerResource) ->
|
||||
new class Customers
|
||||
all: []
|
||||
byID: {}
|
||||
pristineByID: {}
|
||||
|
||||
add: (email) ->
|
||||
params =
|
||||
enterprise_id: CurrentShop.shop.id
|
||||
email: email
|
||||
constructor: ->
|
||||
if $injector.has('customers')
|
||||
@load($injector.get('customers'))
|
||||
|
||||
add: (params) ->
|
||||
CustomerResource.create params, (customer) =>
|
||||
if customer.id
|
||||
@all.unshift customer
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
angular.module("admin.resources").factory 'OrderCycles', ($q, $injector, OrderCycleResource) ->
|
||||
angular.module("admin.resources").factory 'OrderCycles', ($q, $injector, OrderCycleResource, RequestMonitor, StatusMessage) ->
|
||||
new class OrderCycles
|
||||
all: []
|
||||
byID: {}
|
||||
@@ -8,14 +8,13 @@ angular.module("admin.resources").factory 'OrderCycles', ($q, $injector, OrderCy
|
||||
if $injector.has('orderCycles')
|
||||
@load($injector.get('orderCycles'))
|
||||
|
||||
index: (params={}, callback=null) ->
|
||||
OrderCycleResource.index params, (data) =>
|
||||
@load(data)
|
||||
(callback || angular.noop)(data)
|
||||
data
|
||||
index: (params={}) ->
|
||||
request = OrderCycleResource.index params, (data) => @load(data)
|
||||
RequestMonitor.load(request.$promise)
|
||||
request
|
||||
|
||||
load: (orderCycles) ->
|
||||
for orderCycle in orderCycles
|
||||
for orderCycle in orderCycles when orderCycle.id not in Object.keys(@byID)
|
||||
@all.push orderCycle
|
||||
@byID[orderCycle.id] = orderCycle
|
||||
@pristineByID[orderCycle.id] = angular.copy(orderCycle)
|
||||
@@ -30,14 +29,41 @@ angular.module("admin.resources").factory 'OrderCycles', ($q, $injector, OrderCy
|
||||
deferred.reject(response)
|
||||
deferred.promise
|
||||
|
||||
saveChanges: (form) ->
|
||||
changed = {}
|
||||
for id, orderCycle of @byID when not @saved(orderCycle)
|
||||
changed[Object.keys(changed).length] = @changesFor(orderCycle)
|
||||
if Object.keys(changed).length > 0
|
||||
StatusMessage.display('progress', "Saving...")
|
||||
OrderCycleResource.bulkUpdate { order_cycle_set: { collection_attributes: changed } }, (data) =>
|
||||
for orderCycle in data
|
||||
delete orderCycle.coordinator
|
||||
delete orderCycle.producers
|
||||
delete orderCycle.distributors
|
||||
angular.extend(@byID[orderCycle.id], orderCycle)
|
||||
angular.extend(@pristineByID[orderCycle.id], orderCycle)
|
||||
form.$setPristine() if form?
|
||||
StatusMessage.display('success', "Order cycles have been updated.")
|
||||
, (response) =>
|
||||
StatusMessage.display('failure', "Oh no! I was unable to save your changes.")
|
||||
|
||||
saved: (order_cycle) ->
|
||||
@diff(order_cycle).length == 0
|
||||
|
||||
diff: (order_cycle) ->
|
||||
changed = []
|
||||
for attr, value of order_cycle when not angular.equals(value, @pristineByID[order_cycle.id][attr])
|
||||
changed.push attr unless attr is "$$hashKey"
|
||||
changed.push attr if attr in @attrsToSave()
|
||||
changed
|
||||
|
||||
changesFor: (orderCycle) ->
|
||||
changes = { id: orderCycle.id }
|
||||
for attr, value of orderCycle when not angular.equals(value, @pristineByID[orderCycle.id][attr])
|
||||
changes[attr] = orderCycle[attr] if attr in @attrsToSave()
|
||||
changes
|
||||
|
||||
attrsToSave: ->
|
||||
['orders_open_at','orders_close_at']
|
||||
|
||||
resetAttribute: (order_cycle, attribute) ->
|
||||
order_cycle[attribute] = @pristineByID[order_cycle.id][attribute]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
angular.module("admin.resources")
|
||||
.factory "PaymentMethods", ($injector) ->
|
||||
new class PaymentMethods
|
||||
paymentMethods: []
|
||||
all: []
|
||||
byID: {}
|
||||
pristineByID: {}
|
||||
|
||||
@@ -11,6 +11,6 @@ angular.module("admin.resources")
|
||||
|
||||
load: (paymentMethods) ->
|
||||
for paymentMethod in paymentMethods
|
||||
@paymentMethods.push paymentMethod
|
||||
@all.push paymentMethod
|
||||
@byID[paymentMethod.id] = paymentMethod
|
||||
@pristineByID[paymentMethod.id] = angular.copy(paymentMethod)
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
angular.module("admin.resources").factory "Schedules", ($q, $injector, RequestMonitor, ScheduleResource, OrderCycles, Dereferencer, StatusMessage) ->
|
||||
new class Schedules
|
||||
all: []
|
||||
byID: {}
|
||||
|
||||
constructor: ->
|
||||
if $injector.has('schedules')
|
||||
@load($injector.get('schedules'))
|
||||
|
||||
load: (schedules) ->
|
||||
for schedule in schedules
|
||||
@all.push schedule
|
||||
@byID[schedule.id] = schedule
|
||||
|
||||
add: (params) =>
|
||||
ScheduleResource.create params, (schedule) =>
|
||||
@byID[schedule.id] = schedule if schedule.id?
|
||||
Dereferencer.dereference(schedule.order_cycles, OrderCycles.byID)
|
||||
orderCycle.schedules.push(schedule) for orderCycle in schedule.order_cycles
|
||||
StatusMessage.display 'success', "#{t('admin.order_cycles.index.created_schedule')}: '#{schedule.name}'"
|
||||
|
||||
update: (params) =>
|
||||
ScheduleResource.update params, (schedule) =>
|
||||
if schedule.id?
|
||||
Dereferencer.dereference(schedule.order_cycles, OrderCycles.byID)
|
||||
for orderCycle in @byID[schedule.id].order_cycles when orderCycle.id not in schedule.order_cycle_ids
|
||||
if orderCycle.schedules # Only if we need to update the schedules
|
||||
orderCycle.schedules.splice(i, 1) for s, i in orderCycle.schedules by -1 when s.id == schedule.id
|
||||
for orderCycle in schedule.order_cycles when orderCycle.id not in @byID[schedule.id].order_cycle_ids
|
||||
orderCycle.schedules.push(@byID[schedule.id])
|
||||
angular.extend(@byID[schedule.id], schedule)
|
||||
StatusMessage.display 'success', "#{t('admin.order_cycles.index.updated_schedule')}: '#{schedule.name}'"
|
||||
|
||||
remove: (schedule) ->
|
||||
params = id: schedule.id
|
||||
ScheduleResource.destroy params, =>
|
||||
for orderCycle in @byID[schedule.id].order_cycles
|
||||
if orderCycle.schedules # Only if we need to update the schedules
|
||||
orderCycle.schedules.splice(i, 1) for s, i in orderCycle.schedules by -1 when s.id == schedule.id
|
||||
delete @byID[schedule.id]
|
||||
StatusMessage.display 'success', "#{t('admin.order_cycles.index.deleted_schedule')}: '#{schedule.name}'"
|
||||
, (response) =>
|
||||
errors = response.data.errors
|
||||
if errors?
|
||||
InfoDialog.open 'error', errors[0]
|
||||
else
|
||||
InfoDialog.open 'error', "Could not delete schedule: #{schedule.name}"
|
||||
|
||||
index: ->
|
||||
request = ScheduleResource.index (data) => @load(data)
|
||||
RequestMonitor.load(request.$promise)
|
||||
request
|
||||
@@ -1,7 +1,7 @@
|
||||
angular.module("admin.resources")
|
||||
.factory "ShippingMethods", ($injector) ->
|
||||
new class ShippingMethods
|
||||
shippingMethods: []
|
||||
all: []
|
||||
byID: {}
|
||||
pristineByID: {}
|
||||
|
||||
@@ -11,6 +11,6 @@ angular.module("admin.resources")
|
||||
|
||||
load: (shippingMethods) ->
|
||||
for shippingMethod in shippingMethods
|
||||
@shippingMethods.push shippingMethod
|
||||
@all.push shippingMethod
|
||||
@byID[shippingMethod.id] = shippingMethod
|
||||
@pristineByID[shippingMethod.id] = angular.copy(shippingMethod)
|
||||
|
||||
@@ -16,9 +16,9 @@ angular.module("ofn.admin").factory "BulkProducts", (PagedFetcher, dataFetcher,
|
||||
@unpackProduct newProduct
|
||||
@insertProductAfter(product, newProduct)
|
||||
|
||||
updateVariantLists: (serverProducts, productsWithUnsavedVariants) ->
|
||||
for product in productsWithUnsavedVariants
|
||||
server_product = @findProductInList(product.id, serverProducts)
|
||||
updateVariantLists: (serverProducts) ->
|
||||
for server_product in serverProducts
|
||||
product = @findProductInList(server_product.id, @products)
|
||||
product.variants = server_product.variants
|
||||
@loadVariantUnitValues product
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
angular.module("admin.subscriptions").controller "AddressController", ($scope, $filter, StatusMessage, availableCountries) ->
|
||||
$scope.countries = availableCountries
|
||||
$scope.statesFor = (country_id) ->
|
||||
return [] unless country_id
|
||||
$filter('filter')(availableCountries, {id: country_id})[0].states
|
||||
$scope.billStates = $scope.statesFor($scope.subscription.bill_address.country_id)
|
||||
$scope.shipStates = $scope.statesFor($scope.subscription.ship_address.country_id)
|
||||
|
||||
$scope.registerNextCallback 'address', ->
|
||||
$scope.subscription_form.$submitted = true
|
||||
if $scope.subscription_address_form.$valid
|
||||
$scope.subscription_form.$setPristine()
|
||||
StatusMessage.clear()
|
||||
$scope.setView('products')
|
||||
else
|
||||
StatusMessage.display 'failure', t('admin.subscriptions.details.invalid_error')
|
||||
|
||||
$scope.registerBackCallback 'address', ->
|
||||
StatusMessage.clear()
|
||||
$scope.setView('details')
|
||||
|
||||
$scope.$watch 'subscription.bill_address.country_id', (newValue, oldValue) ->
|
||||
$scope.billStates = $scope.statesFor(newValue) if newValue?
|
||||
|
||||
$scope.$watch 'subscription.ship_address.country_id', (newValue, oldValue) ->
|
||||
$scope.shipStates = $scope.statesFor(newValue) if newValue?
|
||||
@@ -0,0 +1,38 @@
|
||||
angular.module("admin.subscriptions").controller "DetailsController", ($scope, $http, CreditCardResource, StatusMessage) ->
|
||||
$scope.cardRequired = false
|
||||
|
||||
$scope.registerNextCallback 'details', ->
|
||||
$scope.subscription_form.$submitted = true
|
||||
if $scope.subscription_details_form.$valid
|
||||
$scope.subscription_form.$setPristine()
|
||||
StatusMessage.clear()
|
||||
$scope.setView('address')
|
||||
else
|
||||
StatusMessage.display 'failure', t('admin.subscriptions.details.invalid_error')
|
||||
|
||||
$scope.$watch "subscription.customer_id", (newValue, oldValue) ->
|
||||
return if !newValue?
|
||||
$scope.loadAddresses(newValue) unless $scope.subscription.id?
|
||||
$scope.loadCreditCards(newValue)
|
||||
|
||||
$scope.$watch "subscription.payment_method_id", (newValue, oldValue) ->
|
||||
return if !newValue?
|
||||
paymentMethod = ($scope.paymentMethods.filter (pm) -> pm.id == newValue)[0]
|
||||
return unless paymentMethod?
|
||||
if paymentMethod.type == "Spree::Gateway::StripeConnect"
|
||||
$scope.cardRequired = true
|
||||
else
|
||||
$scope.cardRequired = false
|
||||
$scope.subscription.credit_card_id = null
|
||||
|
||||
$scope.loadAddresses = (customer_id) ->
|
||||
$http.get("/admin/customers/#{customer_id}/addresses")
|
||||
.success (response) =>
|
||||
delete response.bill_address.id
|
||||
delete response.ship_address.id
|
||||
angular.extend($scope.subscription.bill_address, response.bill_address)
|
||||
angular.extend($scope.subscription.ship_address, response.ship_address)
|
||||
$scope.shipAddressFromBilling() unless response.ship_address.address1?
|
||||
|
||||
$scope.loadCreditCards = (customer_id) ->
|
||||
$scope.creditCards = CreditCardResource.index(customer_id: customer_id)
|
||||
@@ -0,0 +1,10 @@
|
||||
angular.module("admin.subscriptions").controller "OrderUpdateIssuesController", ($scope, OrderCycles) ->
|
||||
$scope.proxyOrders = $scope.options.proxyOrders
|
||||
|
||||
$scope.orderCycleName = (id) ->
|
||||
OrderCycles.byID[id].name
|
||||
|
||||
$scope.orderCycleCloses = (id) ->
|
||||
closes_at = moment(OrderCycles.byID[id].orders_close_at)
|
||||
text = if closes_at > moment() then t('js.closes') else t('js.closed')
|
||||
"#{text} #{closes_at.fromNow()}"
|
||||
@@ -0,0 +1,22 @@
|
||||
angular.module("admin.subscriptions").controller "OrdersPanelController", ($scope, OrderCycles) ->
|
||||
$scope.subscription = $scope.object
|
||||
|
||||
$scope.cancelOrder = (order) ->
|
||||
if confirm(t('are_you_sure'))
|
||||
$scope.subscription.cancelOrder(order)
|
||||
|
||||
$scope.resumeOrder = (order) ->
|
||||
if confirm(t('are_you_sure'))
|
||||
$scope.subscription.resumeOrder(order)
|
||||
|
||||
$scope.orderCycleName = (id) ->
|
||||
OrderCycles.byID[id].name
|
||||
|
||||
$scope.orderCycleCloses = (id) ->
|
||||
oc = OrderCycles.byID[id]
|
||||
return t('js.subscriptions.close_date_not_set') unless oc?.orders_close_at?
|
||||
closes_at = moment(oc.orders_close_at)
|
||||
text = if closes_at > moment() then t('js.subscriptions.closes') else t('js.subscription.closed')
|
||||
"#{text} #{closes_at.fromNow()}"
|
||||
|
||||
$scope.stateText = (state) -> t("spree.order_state.#{state}")
|
||||
@@ -0,0 +1,13 @@
|
||||
angular.module("admin.subscriptions").controller "ProductsController", ($scope, StatusMessage) ->
|
||||
$scope.registerNextCallback 'products', ->
|
||||
$scope.subscription_form.$submitted = true
|
||||
if $scope.subscription.subscription_line_items.length > 0
|
||||
$scope.subscription_form.$setPristine()
|
||||
StatusMessage.clear()
|
||||
$scope.setView('review')
|
||||
else
|
||||
StatusMessage.display 'failure', 'Please add at least one product'
|
||||
|
||||
$scope.registerBackCallback 'products', ->
|
||||
StatusMessage.clear()
|
||||
$scope.setView('address')
|
||||
@@ -0,0 +1,23 @@
|
||||
angular.module("admin.subscriptions").controller "ProductsPanelController", ($scope, Subscriptions, StatusMessage) ->
|
||||
$scope.subscription = $scope.object
|
||||
$scope.distributor_id = $scope.subscription.shop_id
|
||||
$scope.saving = false
|
||||
|
||||
$scope.saved = ->
|
||||
pristine = Subscriptions.pristineByID[$scope.subscription.id].subscription_line_items
|
||||
return false unless angular.equals($scope.subscription.subscription_line_items, pristine)
|
||||
true
|
||||
|
||||
$scope.save = ->
|
||||
$scope.saving = true
|
||||
StatusMessage.display 'progress', 'Saving...'
|
||||
$scope.subscription.update().then (response) ->
|
||||
$scope.saving = false
|
||||
StatusMessage.display 'success', 'Saved'
|
||||
, (response) ->
|
||||
$scope.saving = false
|
||||
if response.data?.errors?
|
||||
keys = Object.keys(response.data.errors)
|
||||
StatusMessage.display 'failure', response.data.errors[keys[0]][0]
|
||||
else
|
||||
StatusMessage.display 'success', 'Saved'
|
||||
@@ -0,0 +1,8 @@
|
||||
angular.module("admin.subscriptions").controller "ReviewController", ($scope, Customers, Schedules, PaymentMethods, ShippingMethods) ->
|
||||
$scope.formatAddress = (a) ->
|
||||
formatted = []
|
||||
formatted.push "#{a.firstname} #{a.lastname}"
|
||||
formatted.push a.address1
|
||||
formatted.push a.city
|
||||
formatted.push a.zipcode
|
||||
formatted.join(", ")
|
||||
@@ -0,0 +1,27 @@
|
||||
angular.module("admin.subscriptions").controller "SubscriptionController", ($scope, Subscription, SubscriptionForm, Customers, Schedules, PaymentMethods, ShippingMethods) ->
|
||||
$scope.subscription = new Subscription()
|
||||
$scope.errors = null
|
||||
$scope.save = null
|
||||
$scope.customers = Customers.all
|
||||
$scope.schedules = Schedules.all
|
||||
$scope.paymentMethods = PaymentMethods.all
|
||||
$scope.shippingMethods = ShippingMethods.all
|
||||
$scope.distributor_id = $scope.subscription.shop_id # variant selector requires distributor_id
|
||||
$scope.view = if $scope.subscription.id? then 'review' else 'details'
|
||||
$scope.nextCallbacks = {}
|
||||
$scope.backCallbacks = {}
|
||||
$scope.creditCards = []
|
||||
$scope.setView = (view) -> $scope.view = view
|
||||
$scope.stepTitleFor = (step) -> t("admin.subscriptions.steps.#{step}")
|
||||
$scope.registerNextCallback = (view, callback) => $scope.nextCallbacks[view] = callback
|
||||
$scope.registerBackCallback = (view, callback) => $scope.backCallbacks[view] = callback
|
||||
$scope.next = -> $scope.nextCallbacks[$scope.view]()
|
||||
$scope.back = -> $scope.backCallbacks[$scope.view]()
|
||||
|
||||
$scope.shipAddressFromBilling = =>
|
||||
angular.extend($scope.subscription.ship_address, $scope.subscription.bill_address)
|
||||
|
||||
$scope.$watch 'subscription_form', ->
|
||||
form = new SubscriptionForm($scope.subscription_form, $scope.subscription)
|
||||
$scope.errors = form.errors
|
||||
$scope.save = form.save
|
||||
@@ -0,0 +1,24 @@
|
||||
angular.module("admin.subscriptions").controller "SubscriptionLineItemsController", ($scope, InfoDialog) ->
|
||||
$scope.newItem = { variant_id: 0, quantity: 1 }
|
||||
|
||||
$scope.addSubscriptionLineItem = ->
|
||||
match = $scope.match()
|
||||
if match
|
||||
if match._destroy
|
||||
angular.extend(match, $scope.newItem)
|
||||
delete match._destroy
|
||||
else
|
||||
InfoDialog.open 'error', t('admin.subscriptions.product_already_in_order')
|
||||
else
|
||||
$scope.subscription_form.$setDirty()
|
||||
$scope.subscription.buildItem($scope.newItem)
|
||||
|
||||
$scope.removeSubscriptionLineItem = (item) ->
|
||||
$scope.subscription_form.$setDirty()
|
||||
$scope.subscription.removeItem(item)
|
||||
|
||||
$scope.match = ->
|
||||
matching = $scope.subscription.subscription_line_items.filter (sli) ->
|
||||
sli.variant_id == $scope.newItem.variant_id
|
||||
return matching[0] if matching.length > 0
|
||||
null
|
||||
@@ -0,0 +1,20 @@
|
||||
angular.module("admin.subscriptions").controller "SubscriptionsController", ($scope, Subscriptions, Columns, RequestMonitor, shops, ShippingMethods, PaymentMethods) ->
|
||||
$scope.columns = Columns.columns
|
||||
$scope.shops = shops
|
||||
$scope.shop_id = if shops.length == 1 then shops[0].id else null
|
||||
$scope.shippingMethodsByID = ShippingMethods.byID
|
||||
$scope.paymentMethodsByID = PaymentMethods.byID
|
||||
$scope.RequestMonitor = RequestMonitor
|
||||
$scope.query = ''
|
||||
|
||||
$scope.$watch "shop_id", ->
|
||||
if $scope.shop_id?
|
||||
$scope.subscriptions = Subscriptions.index("q[shop_id_eq]": $scope.shop_id, "q[canceled_at_null]": true)
|
||||
|
||||
$scope.itemCount = (subscription) ->
|
||||
subscription.subscription_line_items.reduce (sum, sli) ->
|
||||
return sum + sli.quantity
|
||||
, 0
|
||||
|
||||
$scope.filtersApplied = ->
|
||||
$scope.query != ''
|
||||
@@ -0,0 +1,9 @@
|
||||
# Used to display a message before redirecting to a link
|
||||
angular.module("admin.subscriptions").directive "confirmOrderEdit", (ConfirmDialog, $window) ->
|
||||
restrict: "A"
|
||||
link: (scope, element, attrs) ->
|
||||
element.bind "click", (event) ->
|
||||
unless scope.proxyOrder.order_id?
|
||||
event.preventDefault()
|
||||
ConfirmDialog.open('error', t('admin.subscriptions.orders.confirm_edit'), {confirm: t('admin.subscriptions.yes_i_am_sure')}).then ->
|
||||
$window.open(attrs.href)
|
||||
@@ -0,0 +1,28 @@
|
||||
angular.module("admin.subscriptions").directive 'newSubscriptionDialog', ($compile, $window, $templateCache, DialogDefaults, shops) ->
|
||||
restrict: 'A'
|
||||
scope: true
|
||||
link: (scope, element, attr) ->
|
||||
scope.submitted = false
|
||||
scope.shops = shops
|
||||
scope.shop_id = null
|
||||
|
||||
scope.newSubscription = ->
|
||||
scope.new_subscription_form.$setPristine()
|
||||
scope.submitted = true
|
||||
if scope.shop_id?
|
||||
$window.location.href = "/admin/subscriptions/new?subscription[shop_id]=#{scope.shop_id}"
|
||||
return
|
||||
|
||||
# Compile modal template
|
||||
template = $compile($templateCache.get('admin/new_subscription_dialog.html'))(scope)
|
||||
|
||||
# Set Dialog options
|
||||
template.dialog(DialogDefaults)
|
||||
|
||||
# Link opening of dialog to click event on element
|
||||
element.bind 'click', (e) ->
|
||||
if shops.length == 1
|
||||
scope.shop_id = shops[0].id
|
||||
scope.newSubscription()
|
||||
else
|
||||
template.dialog('open')
|
||||
@@ -0,0 +1,5 @@
|
||||
angular.module("admin.subscriptions").factory 'CreditCardResource', ($resource) ->
|
||||
resource = $resource '/admin/customers/:customer_id/cards.json', {},
|
||||
'index':
|
||||
method: 'GET'
|
||||
isArray: true
|
||||
@@ -0,0 +1,6 @@
|
||||
angular.module("admin.subscriptions").factory "Subscription", ($injector, SubscriptionResource) ->
|
||||
class Subscription extends SubscriptionResource
|
||||
|
||||
constructor: ->
|
||||
if $injector.has('subscription')
|
||||
angular.extend(@, $injector.get('subscription'))
|
||||
@@ -0,0 +1,77 @@
|
||||
# Wrapper for actions provided by ngResource
|
||||
# Used to extend the prototype of the subscription resource created by SubscriptionResource
|
||||
|
||||
angular.module("admin.subscriptions").factory 'SubscriptionActions', ($http, $injector, $q, InfoDialog, ConfirmDialog) ->
|
||||
buildItem: (item) ->
|
||||
return false unless item.variant_id > 0
|
||||
return false unless item.quantity > 0
|
||||
data = angular.extend({}, item, { shop_id: @shop_id, schedule_id: @schedule_id })
|
||||
$http.post("/admin/subscription_line_items/build", data).then (response) =>
|
||||
@subscription_line_items.push response.data
|
||||
, (response) =>
|
||||
InfoDialog.open 'error', response.data.errors[0]
|
||||
|
||||
removeItem: (item) ->
|
||||
item._destroy = true
|
||||
|
||||
create: ->
|
||||
@$save().then (response) =>
|
||||
$injector.get('Subscriptions').afterCreate(@id) if $injector.has('Subscriptions')
|
||||
$q.resolve(response)
|
||||
, (response) => $q.reject(response)
|
||||
|
||||
update: ->
|
||||
@$update().then (response) =>
|
||||
$injector.get('Subscriptions').afterUpdate(@id) if $injector.has('Subscriptions')
|
||||
orders_with_issues = @not_closed_proxy_orders.filter((po) -> po.update_issues.length > 0)
|
||||
if orders_with_issues.length > 0
|
||||
InfoDialog.open('error', null, 'admin/order_update_issues_dialog.html', { proxyOrders: orders_with_issues})
|
||||
return $q.reject(response)
|
||||
$q.resolve(response)
|
||||
, (response) => $q.reject(response)
|
||||
|
||||
cancel: ->
|
||||
ConfirmDialog.open('error', t('admin.subscriptions.confirm_cancel_msg'), {cancel: t('back'), confirm: t('admin.subscriptions.yes_i_am_sure')})
|
||||
.then =>
|
||||
@$cancel().then angular.noop, (response) =>
|
||||
if response.data?.errors?.open_orders?
|
||||
options = {cancel: t('admin.subscriptions.no_keep_them'), confirm: t('admin.subscriptions.yes_cancel_them')}
|
||||
ConfirmDialog.open('error', response.data.errors.open_orders, options)
|
||||
.then (=> @$cancel(open_orders: 'cancel')), (=> @$cancel(open_orders: 'keep'))
|
||||
else
|
||||
InfoDialog.open 'error', t('admin.subscriptions.cancel_failure_msg')
|
||||
|
||||
pause: ->
|
||||
ConfirmDialog.open('error', t('admin.subscriptions.confirm_pause_msg'), {confirm: t('admin.subscriptions.yes_i_am_sure')})
|
||||
.then =>
|
||||
@$pause().then angular.noop, (response) =>
|
||||
if response.data?.errors?.open_orders?
|
||||
options = {cancel: t('admin.subscriptions.no_keep_them'), confirm: t('admin.subscriptions.yes_cancel_them')}
|
||||
ConfirmDialog.open('error', response.data.errors.open_orders, options)
|
||||
.then (=> @$pause(open_orders: 'cancel')), (=> @$pause(open_orders: 'keep'))
|
||||
else
|
||||
InfoDialog.open 'error', t('admin.subscriptions.pause_failure_msg')
|
||||
|
||||
unpause: ->
|
||||
ConfirmDialog.open('error', t('admin.subscriptions.confirm_unpause_msg'), {confirm: t('admin.subscriptions.yes_i_am_sure')})
|
||||
.then =>
|
||||
@$unpause().then angular.noop, (response) =>
|
||||
if response.data?.errors?.canceled_orders?
|
||||
InfoDialog.open('info', response.data.errors.canceled_orders)
|
||||
.then (=> @$unpause(canceled_orders: 'notified'))
|
||||
else
|
||||
InfoDialog.open 'error', t('admin.subscriptions.unpause_failure_msg')
|
||||
|
||||
cancelOrder: (order) ->
|
||||
if order.id?
|
||||
$http.put("/admin/proxy_orders/#{order.id}/cancel").then (response) =>
|
||||
angular.extend(order,response.data)
|
||||
, (response) ->
|
||||
InfoDialog.open 'error', response.data.errors[0]
|
||||
|
||||
resumeOrder: (order) ->
|
||||
if order.id?
|
||||
$http.put("/admin/proxy_orders/#{order.id}/resume").then (response) =>
|
||||
angular.extend(order,response.data)
|
||||
, (response) ->
|
||||
InfoDialog.open 'error', response.data.errors[0]
|
||||
@@ -0,0 +1,35 @@
|
||||
angular.module("admin.subscriptions").factory 'SubscriptionForm', ($window, StatusMessage) ->
|
||||
class SubscriptionForm
|
||||
form: null
|
||||
subscription: null
|
||||
errors: {}
|
||||
|
||||
constructor: (form, subscription) ->
|
||||
@form = form
|
||||
@subscription = subscription
|
||||
|
||||
save: =>
|
||||
return @formInvalid() unless @form.$valid
|
||||
delete @errors[k] for k, v of @errors
|
||||
@form.$setPristine()
|
||||
StatusMessage.display 'progress', 'Saving...'
|
||||
if @subscription.id?
|
||||
@subscription.update().then @successCallback, @errorCallback
|
||||
else
|
||||
@subscription.create().then @successCallback, @errorCallback
|
||||
|
||||
successCallback: (response) =>
|
||||
StatusMessage.display 'success', 'Saved. Redirecting...'
|
||||
$window.location.href = "/admin/subscriptions"
|
||||
|
||||
errorCallback: (response) =>
|
||||
if response.data?.errors?
|
||||
angular.extend(@errors, response.data.errors)
|
||||
keys = Object.keys(response.data.errors)
|
||||
StatusMessage.display 'failure', response.data.errors[keys[0]][0]
|
||||
else
|
||||
# Happens when there are sync issues between SO and initialised orders
|
||||
# We save the SO, but open a dialog, so want to stay on the page
|
||||
StatusMessage.display 'success', 'Saved'
|
||||
|
||||
formInvalid: -> StatusMessage.display 'failure', t('admin.subscriptions.details.invalid_error')
|
||||
@@ -0,0 +1,35 @@
|
||||
# Provides additional auxillary functions to instances of SubscriptionResource
|
||||
# Used to extend the extend the protype of the subscription resource created by SubscriptionResource
|
||||
|
||||
angular.module("admin.subscriptions").factory 'SubscriptionFunctions', ($injector) ->
|
||||
estimatedSubtotal: ->
|
||||
@subscription_line_items.reduce (subtotal, item) ->
|
||||
return subtotal if item._destroy
|
||||
subtotal += item.price_estimate * item.quantity
|
||||
, 0
|
||||
|
||||
estimatedFees: ->
|
||||
@shipping_fee_estimate + @payment_fee_estimate
|
||||
|
||||
estimatedTotal: ->
|
||||
@estimatedSubtotal() + @estimatedFees()
|
||||
|
||||
customer: ->
|
||||
return unless @customer_id
|
||||
return unless $injector.has('Customers')
|
||||
$injector.get('Customers').byID[@customer_id]
|
||||
|
||||
schedule: ->
|
||||
return unless @schedule_id
|
||||
return unless $injector.has('Schedules')
|
||||
$injector.get('Schedules').byID[@schedule_id]
|
||||
|
||||
paymentMethod: ->
|
||||
return unless @payment_method_id
|
||||
return unless $injector.has('PaymentMethods')
|
||||
$injector.get('PaymentMethods').byID[@payment_method_id]
|
||||
|
||||
shippingMethod: ->
|
||||
return unless @shipping_method_id
|
||||
return unless $injector.has('ShippingMethods')
|
||||
$injector.get('ShippingMethods').byID[@shipping_method_id]
|
||||
@@ -0,0 +1,32 @@
|
||||
angular.module("admin.subscriptions").factory 'SubscriptionResource', ($resource, SubscriptionActions, SubscriptionFunctions) ->
|
||||
resource = $resource('/admin/subscriptions/:id/:action.json', {}, {
|
||||
'index':
|
||||
method: 'GET'
|
||||
isArray: true
|
||||
'update':
|
||||
method: 'PUT'
|
||||
params:
|
||||
id: '@id'
|
||||
'cancel':
|
||||
method: 'PUT'
|
||||
params:
|
||||
id: '@id'
|
||||
action: 'cancel'
|
||||
open_orders: '@open_orders'
|
||||
'pause':
|
||||
method: 'PUT'
|
||||
params:
|
||||
id: '@id'
|
||||
action: 'pause'
|
||||
open_orders: '@open_orders'
|
||||
'unpause':
|
||||
method: 'PUT'
|
||||
params:
|
||||
id: '@id'
|
||||
action: 'unpause'
|
||||
})
|
||||
|
||||
angular.extend(resource.prototype, SubscriptionActions)
|
||||
angular.extend(resource.prototype, SubscriptionFunctions)
|
||||
|
||||
resource
|
||||
@@ -0,0 +1,27 @@
|
||||
angular.module("admin.subscriptions").factory 'Subscriptions', ($q, SubscriptionResource, Subscription, RequestMonitor) ->
|
||||
new class Subscriptions
|
||||
byID: {}
|
||||
pristineByID: {}
|
||||
|
||||
index: (params={}, callback=null) ->
|
||||
request = SubscriptionResource.index params, (data) => @load(data)
|
||||
RequestMonitor.load(request.$promise)
|
||||
request
|
||||
|
||||
load: (subscriptions) ->
|
||||
for subscription in subscriptions
|
||||
@byID[subscription.id] = subscription
|
||||
@pristineByID[subscription.id] = angular.copy(subscription)
|
||||
|
||||
afterCreate: (id) ->
|
||||
return unless @byID[id]?
|
||||
@pristineByID[id] = angular.copy(@byID[id])
|
||||
|
||||
afterUpdate: (id) ->
|
||||
return unless @byID[id]?
|
||||
@pristineByID[id] = angular.copy(@byID[id])
|
||||
|
||||
afterRemoveItem: (id, deletedItemID) ->
|
||||
return unless @pristineByID[id]?
|
||||
for item, i in @pristineByID[id].subscription_line_items when item.id == deletedItemID
|
||||
@pristineByID[id].subscription_line_items.splice(i, 1)
|
||||
@@ -0,0 +1 @@
|
||||
angular.module("admin.subscriptions", ['ngResource','admin.indexUtils','admin.dropdown'])
|
||||
@@ -1,6 +1,6 @@
|
||||
$(document).ready(function() {
|
||||
$('.datetimepicker').datetimepicker({
|
||||
dateFormat: Spree.translations.date_picker,
|
||||
dateFormat: 'yy-mm-dd',
|
||||
dayNames: Spree.translations.abbr_day_names,
|
||||
dayNamesMin: Spree.translations.abbr_day_names,
|
||||
monthNames: Spree.translations.month_names,
|
||||
|
||||
@@ -14,8 +14,11 @@ angular.module("admin.utils").directive "ofnSelect2", ($sanitize, $timeout, $fil
|
||||
scope.text ?= 'name'
|
||||
scope.multiple ?= false
|
||||
scope.filter ?= -> true
|
||||
scope.placeholder ?= t('admin.choose')
|
||||
|
||||
if scope.data.$promise
|
||||
# Initialize with empty data set, while we wait for data
|
||||
element.select2(data:[], placeholder: scope.placeholder)
|
||||
scope.data.$promise.then -> init()
|
||||
else
|
||||
init()
|
||||
@@ -39,6 +42,7 @@ angular.module("admin.utils").directive "ofnSelect2", ($sanitize, $timeout, $fil
|
||||
item.name = $sanitize(item.name) for item in scope.data
|
||||
element.select2
|
||||
multiple: scope.multiple
|
||||
placeholder: scope.placeholder
|
||||
minimumResultsForSearch: scope.minSearch || 0
|
||||
data: ->
|
||||
filtered = $filter('filter')(scope.data,scope.filter)
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
angular.module("admin.utils").directive "variantAutocomplete", ($timeout) ->
|
||||
restrict: 'C'
|
||||
link: (scope, element, attrs) ->
|
||||
# Make variantAutocomplete do nothing because it is called
|
||||
# from core/app/assets/javascripts/admin/orders/edit.js
|
||||
$.fn.variantAutocomplete = angular.noop
|
||||
|
||||
$timeout ->
|
||||
if $("#variant_autocomplete_template").length > 0
|
||||
variantTemplate = Handlebars.compile($("#variant_autocomplete_template").text())
|
||||
|
||||
if Spree.routes
|
||||
element.parent().children(".options_placeholder").attr "id", element.parent().data("index")
|
||||
element.select2
|
||||
placeholder: "Select a variant"
|
||||
minimumInputLength: 3
|
||||
quietMillis: 300
|
||||
ajax:
|
||||
url: Spree.routes.variants_search
|
||||
datatype: "json"
|
||||
data: (term, page) ->
|
||||
q: term
|
||||
distributor_id: scope.distributor_id
|
||||
order_cycle_id: scope.order_cycle_id
|
||||
results: (data, page) ->
|
||||
results: data
|
||||
formatResult: (variant) ->
|
||||
if variant["images"][0] != undefined && variant["images"][0].image != undefined
|
||||
variant.image = variant.images[0].image.mini_url
|
||||
variantTemplate variant: variant
|
||||
formatSelection: (variant) ->
|
||||
element.parent().children(".options_placeholder").html variant.options_text
|
||||
variant.name
|
||||
@@ -0,0 +1,21 @@
|
||||
angular.module("admin.utils").factory 'ConfirmDialog', ($rootScope, $q, $compile, $templateCache, DialogDefaults) ->
|
||||
new class ConfirmDialog
|
||||
open: (type, message, options) ->
|
||||
deferred = $q.defer()
|
||||
scope = $rootScope.$new()
|
||||
scope.message = message
|
||||
scope.dialog_class = type
|
||||
scope.confirmText = options?.confirm || t('ok')
|
||||
scope.cancelText = options?.cancel || t('cancel')
|
||||
template = $compile($templateCache.get('admin/confirm_dialog.html'))(scope)
|
||||
template.dialog(DialogDefaults)
|
||||
template.dialog('open')
|
||||
scope.confirm = ->
|
||||
deferred.resolve()
|
||||
template.dialog('close')
|
||||
null
|
||||
scope.close = ->
|
||||
deferred.reject()
|
||||
template.dialog('close')
|
||||
null
|
||||
deferred.promise
|
||||
@@ -3,7 +3,8 @@ angular.module("admin.utils").factory "DialogDefaults", ($window) ->
|
||||
hide: { effect: "fade", duration: 300 }
|
||||
autoOpen: false
|
||||
resizable: false
|
||||
width: $window.innerWidth * 0.4;
|
||||
width: $window.innerWidth * 0.4
|
||||
position: ['middle', 100]
|
||||
modal: true
|
||||
open: (event, ui) ->
|
||||
$('.ui-widget-overlay').bind 'click', ->
|
||||
|
||||
@@ -1,12 +1,22 @@
|
||||
angular.module("admin.customers").factory 'InfoDialog', ($rootScope, $compile, $injector, $templateCache, DialogDefaults) ->
|
||||
angular.module("admin.utils").factory 'InfoDialog', ($rootScope, $q, $compile, $templateCache, DialogDefaults) ->
|
||||
new class InfoDialog
|
||||
open: (type, message) ->
|
||||
icon_classes: {
|
||||
error: 'icon-exclamation-sign'
|
||||
info: 'icon-info-sign'
|
||||
}
|
||||
|
||||
open: (type, message, templateUrl='admin/info_dialog.html', options={}) ->
|
||||
deferred = $q.defer()
|
||||
scope = $rootScope.$new()
|
||||
scope.message = message
|
||||
scope.dialog_class = type
|
||||
template = $compile($templateCache.get('admin/info_dialog.html'))(scope)
|
||||
scope.icon_class = @icon_classes[type]
|
||||
scope.options = options
|
||||
template = $compile($templateCache.get(templateUrl))(scope)
|
||||
template.dialog(DialogDefaults)
|
||||
template.dialog('open')
|
||||
scope.close = ->
|
||||
deferred.resolve()
|
||||
template.dialog('close')
|
||||
null
|
||||
deferred.promise
|
||||
|
||||
@@ -1 +1 @@
|
||||
angular.module("admin.utils", ["templates", "ngSanitize"])
|
||||
angular.module("admin.utils", ["templates", "ngSanitize"]).config ($httpProvider) ->
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
$(document).ready ->
|
||||
if $("#variant_autocomplete_template").length > 0
|
||||
window.variantTemplate = Handlebars.compile($("#variant_autocomplete_template").text())
|
||||
|
||||
formatVariantResult = (variant) ->
|
||||
if variant["images"][0] != undefined && variant["images"][0].image != undefined
|
||||
variant.image = variant.images[0].image.mini_url
|
||||
variantTemplate variant: variant
|
||||
|
||||
$.fn.variantAutocomplete = ->
|
||||
if Spree.routes
|
||||
@parent().children(".options_placeholder").attr "id", @parent().data("index")
|
||||
@select2
|
||||
placeholder: "Select a variant"
|
||||
minimumInputLength: 3
|
||||
ajax:
|
||||
url: Spree.routes.variants_search
|
||||
datatype: "json"
|
||||
data: (term, page) ->
|
||||
q: term
|
||||
distributor_id: $("#order_distributor_id").val()
|
||||
order_cycle_id: $("#order_order_cycle_id").val()
|
||||
|
||||
results: (data, page) ->
|
||||
results: data
|
||||
|
||||
formatResult: formatVariantResult
|
||||
formatSelection: (variant) ->
|
||||
$(@element).parent().children(".options_placeholder").html variant.options_text
|
||||
variant.name
|
||||
@@ -23,7 +23,16 @@
|
||||
#
|
||||
#= require angular-backstretch.js
|
||||
#= require angular-flash.min.js
|
||||
#
|
||||
#= require moment
|
||||
#= require moment/en-gb.js
|
||||
#= require moment/es.js
|
||||
#= require moment/fr.js
|
||||
#= require moment/it.js
|
||||
#= require moment/nb.js
|
||||
#= require moment/pt-br.js
|
||||
#= require moment/sv.js
|
||||
#
|
||||
#= require modernizr
|
||||
#
|
||||
#= require foundation
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Darkswarm.controller "LoginCtrl", ($scope, $http, $window, AuthenticationService, Redirections, Loading) ->
|
||||
Darkswarm.controller "LoginCtrl", ($scope, $timeout, $location, $http, $window, AuthenticationService, Redirections, Loading) ->
|
||||
$scope.path = "/login"
|
||||
|
||||
$scope.submit = ->
|
||||
@@ -10,4 +10,18 @@ Darkswarm.controller "LoginCtrl", ($scope, $http, $window, AuthenticationService
|
||||
$window.location.href = $window.location.origin + $window.location.pathname # Strips out hash fragments
|
||||
.error (data) ->
|
||||
Loading.clear()
|
||||
$scope.errors = data.message
|
||||
$scope.errors = data.message || data.error
|
||||
$scope.user_unconfirmed = (data.error == t('devise.failure.unconfirmed'))
|
||||
|
||||
$scope.resend_confirmation = ->
|
||||
$http.post("/user/spree_user/confirmation", {spree_user: $scope.spree_user}).success (data)->
|
||||
$scope.messages = t('devise.confirmations.send_instructions')
|
||||
.error (data) ->
|
||||
$scope.errors = t('devise.confirmations.failed_to_send')
|
||||
|
||||
$timeout ->
|
||||
if angular.isDefined($location.search()['validation'])
|
||||
if $location.search()['validation'] == 'confirmed'
|
||||
$scope.messages = t('devise.confirmations.confirmed')
|
||||
if $location.search()['validation'] == 'not_confirmed'
|
||||
$scope.errors = t('devise.confirmations.not_confirmed')
|
||||
|
||||
@@ -8,10 +8,8 @@ Darkswarm.controller "SignupCtrl", ($scope, $http, $window, $location, Redirecti
|
||||
password: null
|
||||
|
||||
$scope.submit = ->
|
||||
$http.post("/user/spree_user", {spree_user: $scope.spree_user}).success (data)->
|
||||
if Redirections.after_login
|
||||
$window.location.href = $window.location.origin + Redirections.after_login
|
||||
else
|
||||
$window.location.href = $window.location.origin + $window.location.pathname # Strips out hash fragments
|
||||
$http.post("/user/spree_user", {spree_user: $scope.spree_user, return_url: $location.absUrl()}).success (data)->
|
||||
$scope.errors = {email: null, password: null}
|
||||
$scope.messages = t('devise.user_registrations.spree_user.signed_up_but_unconfirmed')
|
||||
.error (data) ->
|
||||
$scope.errors = data
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
# Old aliases before i18n-js was introduced.
|
||||
# TODO - delete it after everything is moved to i18n-js
|
||||
|
||||
# Declares the translation function t.
|
||||
# You can use translate('login') or t('login') in Javascript.
|
||||
window.translate = (key, options = {}) ->
|
||||
|
||||
@@ -4,10 +4,8 @@ Darkswarm.factory "AuthenticationService", (Navigation, $modal, $location, Redir
|
||||
selectedPath: "/login"
|
||||
|
||||
constructor: ->
|
||||
if $location.path() in ["/login", "/signup", "/forgot"] && location.pathname isnt '/register/auth'
|
||||
@open $location.path()
|
||||
else if location.pathname is '/register/auth'
|
||||
@open '/signup', 'registration_authentication.html'
|
||||
if $location.path() in ["/login", "/signup", "/forgot"] || location.pathname is '/register/auth'
|
||||
@open @initialTab(), @initialTemplate()
|
||||
|
||||
open: (path = false, template = 'authentication.html') =>
|
||||
@modalInstance = $modal.open
|
||||
@@ -17,6 +15,23 @@ Darkswarm.factory "AuthenticationService", (Navigation, $modal, $location, Redir
|
||||
@selectedPath = path || @selectedPath
|
||||
Navigation.navigate @selectedPath
|
||||
|
||||
# Opens the /login tab if returning from email confirmation,
|
||||
# the /signup tab if opened from the enterprise registration page,
|
||||
# otherwise opens whichever tab is selected in the URL params ('/login', '/signup', or '/forgot')
|
||||
initialTab: ->
|
||||
if angular.isDefined($location.search()['validation'])
|
||||
'/login'
|
||||
else if location.pathname is '/register/auth'
|
||||
'/signup'
|
||||
else
|
||||
$location.path()
|
||||
|
||||
# Loads the registration page modal when needed, otherwise the default modal
|
||||
initialTemplate: ->
|
||||
if location.pathname is '/register/auth'
|
||||
'registration_authentication.html'
|
||||
else
|
||||
'authentication.html'
|
||||
|
||||
select: (path)=>
|
||||
@selectedPath = path
|
||||
|
||||
@@ -2,7 +2,6 @@ Darkswarm.factory "EnterpriseRegistrationService", ($http, RegistrationService,
|
||||
new class EnterpriseRegistrationService
|
||||
enterprise:
|
||||
user_ids: [CurrentUser.id]
|
||||
email: CurrentUser.email
|
||||
email_address: CurrentUser.email
|
||||
address: {}
|
||||
country: availableCountries[0]
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#confirm-dialog{ ng: { class: "dialog_class" } }
|
||||
.message.clearfix.margin-bottom-30
|
||||
.icon.text-center
|
||||
%i.icon-question-sign
|
||||
.text{ ng: { bind: "::message" } }
|
||||
.action-buttons.text-center
|
||||
%button.cancel{ ng: { click: "close()", bind: "::cancelText" } }
|
||||
%button.confirm.red{ ng: { click: "confirm()", bind: "::confirmText" } }
|
||||
@@ -2,7 +2,7 @@
|
||||
%h2 {{ addressType === 'bill_address' ? "#{t('admin.customers.index.edit_bill_address')}" : "#{t('admin.customers.index.edit_ship_address')}" }}
|
||||
%form{ name: 'edit_address_form', novalidate: true, ng: { submit: 'updateAddress()'}}
|
||||
.row
|
||||
= t('admin.customers.index.required_fileds')
|
||||
{{ 'admin.customers.index.required_fileds' | t }}
|
||||
(
|
||||
%span.required *
|
||||
)
|
||||
@@ -11,67 +11,64 @@
|
||||
%table.no-borders
|
||||
%tr
|
||||
%td{style: 'width: 30%'}
|
||||
= t('spree.firstname')
|
||||
{{ 'first_name' | t }}
|
||||
%span.required *
|
||||
%td
|
||||
%input{ type: 'text', name: 'firstname', required: true, ng: { model: 'address.firstname'} }
|
||||
%tr
|
||||
%td
|
||||
= t('spree.lastname')
|
||||
{{ 'last_name' | t }}
|
||||
%span.required *
|
||||
%td
|
||||
%input{ type: 'text', name: 'lastname', required: true, ng: { model: 'address.lastname'} }
|
||||
%tr
|
||||
%td
|
||||
= t('spree.street_address')
|
||||
{{ 'address' | t }}
|
||||
%span.required *
|
||||
%td
|
||||
%input{ type: 'text', name: 'address1', required: true, ng: { model: 'address.address1'} }
|
||||
%tr
|
||||
%td
|
||||
= t('spree.street_address_1')
|
||||
{{ 'address2' | t }}
|
||||
%td
|
||||
%input{ type: 'text', name: 'address2', ng: { model: 'address.address2'} }
|
||||
%tr
|
||||
%td
|
||||
= t('spree.city')
|
||||
{{ 'city' | t }}
|
||||
%span.required *
|
||||
%td
|
||||
%input{ type: 'text', name: 'city', required: true, ng: { model: 'address.city'} }
|
||||
%tr
|
||||
%td
|
||||
= t('spree.zipcode')
|
||||
{{ 'postcode' | t }}
|
||||
%span.required *
|
||||
%td
|
||||
%input{ type: 'text', name: 'zipcode', required: true, ng: { model: 'address.zipcode'} }
|
||||
%tr
|
||||
%td
|
||||
= t('spree.country')
|
||||
{{ 'country' | t }}
|
||||
%span.required *
|
||||
%td
|
||||
%select{ name: 'country', required: true, ng: { model: 'address.country_id' } }
|
||||
%option{value: ''}
|
||||
= t('admin.customers.index.select_country')
|
||||
%option{ ng: { repeat: 'country in availableCountries' }, value: '{{country.id}}' }
|
||||
{{country.name}}
|
||||
%input.ofn-select2.fullwidth#country_id{ type: 'number',
|
||||
name: 'country_id', required: true,
|
||||
placeholder: "{{ 'admin.customers.index.select_country' | t }}",
|
||||
data: 'availableCountries', ng: { model: 'address.country_id' } }
|
||||
%tr
|
||||
%td
|
||||
= t('spree.state')
|
||||
{{ 'state' | t }}
|
||||
%span.required *
|
||||
%td
|
||||
%select{ name: 'state', required: true, ng: { model: 'address.state_id' } }
|
||||
%option{value: ''}
|
||||
= t('admin.customers.index.select_state')
|
||||
%option{ ng: { repeat: 'state in states' }, value: '{{state.id}}' }
|
||||
{{state.name}}
|
||||
%input.ofn-select2.fullwidth#state_id{ type: 'number',
|
||||
name: 'state_id', required: true,
|
||||
placeholder: "{{ 'admin.customers.index.select_state' | t }}",
|
||||
data: 'states', ng: { model: 'address.state_id' } }
|
||||
|
||||
%tr
|
||||
%td
|
||||
= t('spree.phone')
|
||||
{{ 'phone' | t }}
|
||||
%span.required *
|
||||
%td
|
||||
%input{ type: 'text', name: 'phone', required: true, ng: { model: 'address.phone'} }
|
||||
|
||||
.text-center
|
||||
%input.button.red.icon-plus{ type: 'submit', value: t('admin.customers.index.update_address')}
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#info-dialog{ ng: { class: "dialog_class" } }
|
||||
.message.clearfix.margin-bottom-30
|
||||
.icon.text-center
|
||||
%i.icon-exclamation-sign
|
||||
%i{ ng: { class: "icon_class" } }
|
||||
.text
|
||||
{{ message }}
|
||||
.action-buttons.text-center
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.ofn-drop-down
|
||||
%span
|
||||
%i.icon-check
|
||||
= t('admin.actions')
|
||||
{{ 'admin.actions' | t }}
|
||||
%i{ 'ng-class' => "expanded && 'icon-caret-up' || !expanded && 'icon-caret-down'" }
|
||||
%div.menu{ 'ng-show' => "expanded" }
|
||||
%a.menu_item{ 'ng-repeat' => "link in links", href: '{{link.url}}', target: "{{link.target || '_self'}}", data: { method: "{{ link.method || 'get' }}", confirm: "{{link.confirm}}" } }
|
||||
|
||||
@@ -1,19 +1,25 @@
|
||||
#tag-rule-help
|
||||
.margin-bottom-30.text-center
|
||||
.text-big
|
||||
= t('js.admin.modals.tag_rule_help.title')
|
||||
{{ 'js.admin.modals.tag_rule_help.title' | t }}
|
||||
|
||||
.margin-bottom-30
|
||||
.text-normal= t('js.admin.modals.tag_rule_help.overview')
|
||||
%p= t('js.admin.modals.tag_rule_help.overview_text')
|
||||
.text-normal
|
||||
{{ 'js.admin.modals.tag_rule_help.overview' | t }}
|
||||
%p
|
||||
{{ 'js.admin.modals.tag_rule_help.overview_text' | t }}
|
||||
|
||||
.margin-bottom-30
|
||||
.text-normal= t('js.admin.modals.tag_rule_help.by_default_rules')
|
||||
%p= t('js.admin.modals.tag_rule_help.by_default_rules_text')
|
||||
.text-normal
|
||||
{{ 'js.admin.modals.tag_rule_help.by_default_rules' | t }}
|
||||
%p
|
||||
{{ 'js.admin.modals.tag_rule_help.by_default_rules_text' | t }}
|
||||
|
||||
.margin-bottom-30
|
||||
.text-normal= t('js.admin.modals.tag_rule_help.customer_tagged_rules')
|
||||
%p= t('js.admin.modals.tag_rule_help.customer_tagged_rules_text')
|
||||
.text-normal
|
||||
{{ 'js.admin.modals.tag_rule_help.customer_tagged_rules' | t }}
|
||||
%p
|
||||
{{ 'js.admin.modals.tag_rule_help.customer_tagged_rules_text' | t }}
|
||||
|
||||
.text-center
|
||||
%input.button.red.icon-plus{ type: 'button', value: t('js.admin.modals.got_it'), ng: { click: 'close()' } }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#new-customer-dialog
|
||||
.text-normal.margin-bottom-30.text-center
|
||||
= t('admin.customers.index.add_a_new_customer_for', shop_name: "{{ CurrentShop.shop.name }}:")
|
||||
{{ 'admin.customers.index.add_a_new_customer_for' | t:{ shop_name: CurrentShop.shop.name } }}
|
||||
|
||||
%form{ name: 'new_customer_form', novalidate: true, ng: { submit: "addCustomer()" }}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
%input.fullwidth{ type: 'email', name: 'email', required: true, placeholder: t('admin.customers.index.customer_placeholder'), ng: { model: "email" } }
|
||||
%div{ ng: { show: "submitted && new_customer_form.$pristine" } }
|
||||
.error{ ng: { show: "(new_customer_form.email.$error.email || new_customer_form.email.$error.required)" } }
|
||||
= t('admin.customers.index.valid_email_error')
|
||||
{{ 'admin.customers.index.valid_email_error' | t }}
|
||||
.error{ ng: { repeat: "error in errors", bind: "error" } }
|
||||
|
||||
.text-center
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#new-subscription-dialog
|
||||
.text-normal.margin-bottom-30.text-center
|
||||
= t('admin.subscriptions.index.please_select_a_shop')
|
||||
|
||||
%form{ name: 'new_subscription_form', novalidate: true, ng: { submit: "newSubscription()" }}
|
||||
|
||||
.text-center.margin-bottom-30
|
||||
%input.ofn-select2.fullwidth#new_subscription_shop_id{ ng: { model: 'shop_id' }, required: true, name: 'shop_id', data: 'shops' }
|
||||
%div{ ng: { show: "submitted && new_subscription_form.$pristine" } }
|
||||
.error{ ng: { show: "new_subscription_form.shop_id.$error.required" } }
|
||||
= t('admin.subscriptions.index.please_select_a_shop')
|
||||
|
||||
.text-center
|
||||
%input.button.red.icon-plus{ type: 'submit', value: t('continue') }
|
||||
@@ -1,6 +1,6 @@
|
||||
#new-tag-rule-dialog
|
||||
.text-normal.margin-bottom-30.text-center
|
||||
= t('js.admin.new_tag_rule_dialog.select_rule_type')
|
||||
{{ 'js.admin.new_tag_rule_dialog.select_rule_type' | t }}
|
||||
|
||||
.text-center.margin-bottom-30
|
||||
-# %select.fullwidth{ 'select2-min-search' => 5, 'ng-model' => 'newRuleType', 'ng-options' => 'ruleType.id as ruleType.name for ruleType in availableRuleTypes' }
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
%table
|
||||
%tr
|
||||
%td#available-order-cycles
|
||||
Available
|
||||
.order-cycles
|
||||
.order-cycle{ ng: { repeat: 'orderCycle in orderCycles | available:selectedOrderCycles as availableOrderCycles', click: 'selections.available = orderCycle', dblclick: 'add(orderCycle)', class: '{selected: selections.available == orderCycle}' } }
|
||||
{{ orderCycle.name }}
|
||||
%td#add-remove-buttons
|
||||
%a.add.button{ href: 'javascript:void(0)', ng: { click: 'add()' } }
|
||||
%i.icon-chevron-right
|
||||
%a.remove.button{ href: 'javascript:void(0)', ng: { click: 'remove()' } }
|
||||
%i.icon-chevron-left
|
||||
%td#selected-order-cycles
|
||||
Selected
|
||||
.order-cycles
|
||||
.order-cycle{ ng: { repeat: 'orderCycle in selectedOrderCycles', click: 'selections.selected = orderCycle', dblclick: 'remove(orderCycle)', class: '{selected: selections.selected == orderCycle}' } }
|
||||
{{ orderCycle.name }}
|
||||
.error{ ng: { repeat: "error in errors", bind: "error" } }
|
||||
@@ -2,128 +2,162 @@
|
||||
.alpha.eight.columns
|
||||
%div{ ng: { if: "!enterprise.is_primary_producer", switch: "enterprise.sells" } }
|
||||
.info{ ng: { switch: { when: "none" } } }
|
||||
%h3= t('js.admin.panels.enterprise_package.hub_profile')
|
||||
%h3
|
||||
{{ 'js.admin.panels.enterprise_package.hub_profile' | t }}
|
||||
|
||||
%p
|
||||
%strong= t('js.admin.panels.enterprise_package.hub_profile_cost')
|
||||
%strong
|
||||
{{ 'js.admin.panels.enterprise_package.hub_profile_cost' | t }}
|
||||
|
||||
%p= t('js.admin.panels.enterprise_package.hub_profile_text1')
|
||||
%p
|
||||
{{ 'js.admin.panels.enterprise_package.hub_profile_text1' | t }}
|
||||
|
||||
%p= t('js.admin.panels.enterprise_package.hub_profile_text2')
|
||||
%p
|
||||
{{ 'js.admin.panels.enterprise_package.hub_profile_text2' | t }}
|
||||
|
||||
.info{ ng: { switch: { when: "any" } } }
|
||||
%h3= t('js.admin.panels.enterprise_package.hub_shop')
|
||||
%h3
|
||||
{{ 'js.admin.panels.enterprise_package.hub_shop' | t }}
|
||||
|
||||
%p
|
||||
%strong
|
||||
%monthly-pricing-description{ joiner: "comma" }
|
||||
|
||||
%p= t('js.admin.panels.enterprise_package.hub_shop_text1')
|
||||
%p
|
||||
{{ 'js.admin.panels.enterprise_package.hub_shop_text1' | t }}
|
||||
|
||||
%p= t('js.admin.panels.enterprise_package.hub_shop_text2')
|
||||
%p
|
||||
{{ 'js.admin.panels.enterprise_package.hub_shop_text2' | t }}
|
||||
|
||||
%p= t('js.admin.panels.enterprise_package.hub_shop_text3')
|
||||
%p
|
||||
{{ 'js.admin.panels.enterprise_package.hub_shop_text3' | t }}
|
||||
|
||||
.info{ ng: { switch: { default: true } } }
|
||||
%h3
|
||||
= t('js.admin.panels.enterprise_package.choose_package')
|
||||
{{ 'js.admin.panels.enterprise_package.choose_package' | t }}
|
||||
%i.icon-arrow-right
|
||||
|
||||
%p
|
||||
%strong= t('js.admin.panels.enterprise_package.choose_package_text1')
|
||||
%strong
|
||||
{{ 'js.admin.panels.enterprise_package.choose_package_text1' | t }}
|
||||
|
||||
%p
|
||||
= t('js.admin.panels.enterprise_package.choose_package_text2')
|
||||
{{ 'js.admin.panels.enterprise_package.choose_package_text2' | t }}
|
||||
|
||||
%div{ ng: { if: "enterprise.is_primary_producer", switch: "enterprise.sells" } }
|
||||
.info{ ng: { switch: { when: "none" } } }
|
||||
%h3= t('js.admin.panels.enterprise_package.profile_only')
|
||||
%h3
|
||||
{{ 'js.admin.panels.enterprise_package.profile_only' | t }}
|
||||
|
||||
%p
|
||||
%strong= t('js.admin.panels.enterprise_package.profile_only_cost')
|
||||
%strong
|
||||
{{ 'js.admin.panels.enterprise_package.profile_only_cost' | t }}
|
||||
|
||||
%p= t('js.admin.panels.enterprise_package.profile_only_text1')
|
||||
%p
|
||||
{{ 'js.admin.panels.enterprise_package.profile_only_text1' | t }}
|
||||
|
||||
%p= t('js.admin.panels.enterprise_package.profile_only_text2')
|
||||
%p
|
||||
{{ 'js.admin.panels.enterprise_package.profile_only_text2' | t }}
|
||||
|
||||
%p= t('js.admin.panels.enterprise_package.profile_only_text3')
|
||||
%p
|
||||
{{ 'js.admin.panels.enterprise_package.profile_only_text3' | t }}
|
||||
|
||||
.info{ ng: { switch: { when: "own" } } }
|
||||
%h3= t('js.admin.panels.enterprise_package.producer_shop')
|
||||
%h3
|
||||
{{ 'js.admin.panels.enterprise_package.producer_shop' | t }}
|
||||
|
||||
%p
|
||||
%strong
|
||||
%monthly-pricing-description{ joiner: "comma" }
|
||||
|
||||
%p= t('js.admin.panels.enterprise_package.producer_shop_text1')
|
||||
%p
|
||||
{{ 'js.admin.panels.enterprise_package.producer_shop_text1' | t }}
|
||||
|
||||
%p= t('js.admin.panels.enterprise_package.producer_shop_text2')
|
||||
%p
|
||||
{{ 'js.admin.panels.enterprise_package.producer_shop_text2' | t }}
|
||||
|
||||
.info{ ng: { switch: { when: "any" } } }
|
||||
%h3= t('js.admin.panels.enterprise_package.producer_hub')
|
||||
%h3
|
||||
{{ 'js.admin.panels.enterprise_package.producer_hub' | t }}
|
||||
|
||||
%p
|
||||
%strong
|
||||
%monthly-pricing-description{ joiner: "comma" }
|
||||
|
||||
%p= t('js.admin.panels.enterprise_package.producer_hub_text1')
|
||||
%p
|
||||
{{ 'js.admin.panels.enterprise_package.producer_hub_text1' | t }}
|
||||
|
||||
%p= t('js.admin.panels.enterprise_package.producer_hub_text2')
|
||||
%p
|
||||
{{ 'js.admin.panels.enterprise_package.producer_hub_text2' | t }}
|
||||
|
||||
%p= t('js.admin.panels.enterprise_package.producer_hub_text3')
|
||||
%p
|
||||
{{ 'js.admin.panels.enterprise_package.producer_hub_text3' | t }}
|
||||
|
||||
.info{ ng: { switch: { default: true } } }
|
||||
%h3
|
||||
= t('js.admin.panels.enterprise_package.choose_package')
|
||||
{{ 'js.admin.panels.enterprise_package.choose_package' | t }}
|
||||
%i.icon-arrow-right
|
||||
|
||||
%p
|
||||
%strong= t('js.admin.panels.enterprise_package.choose_package_text1')
|
||||
%strong
|
||||
{{ 'js.admin.panels.enterprise_package.choose_package_text1' | t }}
|
||||
|
||||
%p
|
||||
= t('js.admin.panels.enterprise_package.choose_package_text2')
|
||||
{{ 'js.admin.panels.enterprise_package.choose_package_text2' | t }}
|
||||
|
||||
.omega.eight.columns{ ng: { switch: "enterprise.is_primary_producer" } }
|
||||
%div{ ng: { switch: { when: "false" } } }
|
||||
%a.button.selector.hub-profile{ ng: { click: "enterprise.owned && (enterprise.sells='none')", class: "{selected: enterprise.sells=='none', disabled: !enterprise.owned}" } }
|
||||
.top
|
||||
%h3= t('js.admin.panels.enterprise_package.profile_only')
|
||||
%p= t('js.admin.panels.enterprise_package.get_listing')
|
||||
.bottom= t('js.admin.panels.enterprise_package.always_free')
|
||||
%h3
|
||||
{{ 'js.admin.panels.enterprise_package.profile_only' | t }}
|
||||
%p
|
||||
{{ 'js.admin.panels.enterprise_package.get_listing' | t }}
|
||||
.bottom
|
||||
{{ 'js.admin.panels.enterprise_package.always_free' | t }}
|
||||
%a.button.selector.hub{ ng: { click: "enterprise.owned && (enterprise.sells='any')", class: "{selected: enterprise.sells=='any', disabled: !enterprise.owned}" } }
|
||||
.top
|
||||
%h3= t('js.admin.panels.enterprise_package.hub_shop')
|
||||
%p= t('js.admin.panels.enterprise_package.sell_produce_others')
|
||||
%h3
|
||||
{{ 'js.admin.panels.enterprise_package.hub_shop' | t }}
|
||||
%p
|
||||
{{ 'js.admin.panels.enterprise_package.sell_produce_others' | t }}
|
||||
.bottom
|
||||
%monthly-pricing-description{ joiner: "newline" }
|
||||
|
||||
%div{ ng: { switch: { when: "true" } } }
|
||||
%a.button.selector.producer-profile{ ng: { click: "enterprise.owned && (enterprise.sells='none')", class: "{selected: enterprise.sells=='none', disabled: !enterprise.owned}" } }
|
||||
.top
|
||||
%h3= t('js.admin.panels.enterprise_package.profile_only')
|
||||
%p= t('js.admin.panels.enterprise_package.get_listing')
|
||||
.bottom= t('js.admin.panels.enterprise_package.always_free')
|
||||
%h3
|
||||
{{ 'js.admin.panels.enterprise_package.profile_only' | t }}
|
||||
%p
|
||||
{{ 'js.admin.panels.enterprise_package.get_listing' | t }}
|
||||
.bottom
|
||||
{{ 'js.admin.panels.enterprise_package.always_free' | t }}
|
||||
%a.button.selector.producer-shop{ ng: { click: "enterprise.owned && (enterprise.sells='own')", class: "{selected: enterprise.sells=='own', disabled: !enterprise.owned}" } }
|
||||
.top
|
||||
%h3= t('js.admin.panels.enterprise_package.producer_shop')
|
||||
%p= t('js.admin.panels.enterprise_package.sell_own_produce')
|
||||
%h3
|
||||
{{ 'js.admin.panels.enterprise_package.producer_shop' | t }}
|
||||
%p
|
||||
{{ 'js.admin.panels.enterprise_package.sell_own_produce' | t }}
|
||||
.bottom
|
||||
%monthly-pricing-description{ joiner: "newline" }
|
||||
|
||||
%a.button.selector.producer-hub{ ng: { click: "enterprise.owned && (enterprise.sells='any')", class: "{selected: enterprise.sells=='any', disabled: !enterprise.owned}" } }
|
||||
.top
|
||||
%h3= t('js.admin.panels.enterprise_package.producer_hub')
|
||||
%p= t('js.admin.panels.enterprise_package.sell_both')
|
||||
%h3
|
||||
{{ 'js.admin.panels.enterprise_package.producer_hub' | t }}
|
||||
%p
|
||||
{{ 'js.admin.panels.enterprise_package.sell_both' | t }}
|
||||
.bottom
|
||||
%monthly-pricing-description{ joiner: "newline" }
|
||||
|
||||
%a.button.update.fullwidth{ ng: { show: "enterprise.owned", class: "{disabled: saved() && !saving, saving: saving}", click: "save()" } }
|
||||
%span{ ng: {hide: "saved() || saving" } }
|
||||
= t('js.admin.panels.save')
|
||||
{{ 'js.admin.panels.save' | t }}
|
||||
%i.icon-save
|
||||
%span{ ng: {show: "saved() && !saving" } }
|
||||
= t('js.admin.panels.saved')
|
||||
{{ 'js.admin.panels.saved' | t }}
|
||||
%i.icon-ok-sign
|
||||
%span{ ng: {show: "saving" } }
|
||||
= t('js.admin.panels.saving')
|
||||
{{ 'js.admin.panels.saving' | t }}
|
||||
%i.icon-refresh
|
||||
|
||||
@@ -1,37 +1,47 @@
|
||||
.row.enterprise_producer_panel{ ng: { controller: 'indexProducerPanelCtrl' } }
|
||||
.alpha.eight.columns
|
||||
.info{ ng: { show: "enterprise.is_primary_producer==true" } }
|
||||
%h3= t('js.admin.panels.enterprise_producer.producer')
|
||||
%p= t('js.admin.panels.enterprise_producer.producer_text1')
|
||||
|
||||
%p= t('js.admin.panels.enterprise_producer.producer_text2')
|
||||
%h3
|
||||
{{ 'js.admin.panels.enterprise_producer.producer' | t }}
|
||||
%p
|
||||
{{ 'js.admin.panels.enterprise_producer.producer_text1' | t }}
|
||||
%p
|
||||
{{ 'js.admin.panels.enterprise_producer.producer_text2' | t }}
|
||||
|
||||
.info{ ng: { show: "enterprise.is_primary_producer==false" } }
|
||||
%h3= t('js.admin.panels.enterprise_producer.non_producer')
|
||||
%p= t('js.admin.panels.enterprise_producer.non_producer_text1')
|
||||
|
||||
%p= t('js.admin.panels.enterprise_producer.non_producer_text2')
|
||||
%h3
|
||||
{{ 'js.admin.panels.enterprise_producer.non_producer' | t }}
|
||||
%p
|
||||
{{ 'js.admin.panels.enterprise_producer.non_producer_text1' | t }}
|
||||
%p
|
||||
{{ 'js.admin.panels.enterprise_producer.non_producer_text2' | t }}
|
||||
|
||||
.omega.eight.columns
|
||||
%a.button.selector.producer{ ng: { click: 'enterprise.owned && changeToProducer()', class: "{selected: enterprise.is_primary_producer==true, disabled: !enterprise.owned}" } }
|
||||
.top
|
||||
%h3= t('js.admin.panels.enterprise_producer.producer')
|
||||
%p= t('js.admin.panels.enterprise_producer.producer_desc')
|
||||
.bottom= t('js.admin.panels.enterprise_producer.producer_example')
|
||||
%h3
|
||||
{{ 'js.admin.panels.enterprise_producer.producer' | t }}
|
||||
%p
|
||||
{{ 'js.admin.panels.enterprise_producer.producer_desc' | t }}
|
||||
.bottom
|
||||
{{ 'js.admin.panels.enterprise_producer.producer_example' | t }}
|
||||
|
||||
%a.button.selector.non-producer{ ng: { click: 'enterprise.owned && changeToNonProducer()', class: "{selected: enterprise.is_primary_producer==false, disabled: !enterprise.owned}" } }
|
||||
.top
|
||||
%h3= t('js.admin.panels.enterprise_producer.non_producer')
|
||||
%p= t('js.admin.panels.enterprise_producer.non_producer_desc')
|
||||
.bottom= t('js.admin.panels.enterprise_producer.non_producer_example')
|
||||
%h3
|
||||
{{ 'js.admin.panels.enterprise_producer.non_producer' | t }}
|
||||
%p
|
||||
{{ 'js.admin.panels.enterprise_producer.non_producer_desc' | t }}
|
||||
.bottom
|
||||
{{ 'js.admin.panels.enterprise_producer.non_producer_example' | t }}
|
||||
|
||||
%a.button.update.fullwidth{ ng: { show: "enterprise.owned", class: "{disabled: saved() && !saving, saving: saving}", click: "save()" } }
|
||||
%span{ ng: {hide: "saved() || saving" } }
|
||||
= t('js.admin.panels.save')
|
||||
{{ 'js.admin.panels.save' | t }}
|
||||
%i.icon-save
|
||||
%span{ ng: {show: "saved() && !saving" } }
|
||||
= t('js.admin.panels.saved')
|
||||
{{ 'js.admin.panels.saved' | t }}
|
||||
%i.icon-ok-sign
|
||||
%span{ ng: {show: "saving" } }
|
||||
= t('js.admin.panels.saving')
|
||||
{{ 'js.admin.panels.saving' | t }}
|
||||
%i.icon-refresh
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
.alpha.omega.sixteen.columns
|
||||
%h4.status-ok.text-center{ ng: { show: "issues.length == 0 && warnings.length == 0" } }
|
||||
%i.icon-ok-sign
|
||||
= t('js.admin.panels.enterprise_status.status_title', name: '{{ object.name }}')
|
||||
{{ 'js.admin.panels.enterprise_status.status_title' | t:{ name: object.name } }}
|
||||
|
||||
%table{ ng: { show: "issues.length > 0 || warnings.length > 0" } }
|
||||
%thead
|
||||
%th.severity
|
||||
= t('js.admin.panels.enterprise_status.severity')
|
||||
{{ 'js.admin.panels.enterprise_status.severity' | t }}
|
||||
%th.description
|
||||
= t('js.admin.panels.enterprise_status.description')
|
||||
{{ 'js.admin.panels.enterprise_status.description' | t }}
|
||||
%th.resolve
|
||||
= t('js.admin.panels.enterprise_status.resolve')
|
||||
{{ 'js.admin.panels.enterprise_status.resolve' | t }}
|
||||
%tr{ ng: { repeat: "issue in issues"} }
|
||||
%td.severity
|
||||
%i.icon-warning-sign.issue
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
'ng-model' => 'exchange.select_all_variants',
|
||||
'ng-change' => 'setExchangeVariants(exchange, incomingExchangeVariantsFor(exchange.enterprise_id), exchange.select_all_variants)',
|
||||
'id' => 'order_cycle_outgoing_exchange_{{ $parent.$index }}_select_all_variants' }
|
||||
= t('admin.select_all')
|
||||
{{ 'admin.select_all' | t }}
|
||||
|
||||
.exchange-products
|
||||
-# Scope product list based on permissions the current user has to view variants in this exchange
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
'ng-model' => 'exchange.select_all_variants',
|
||||
'ng-change' => 'setExchangeVariants(exchange, suppliedVariants(exchange.enterprise_id), exchange.select_all_variants)',
|
||||
'id' => 'order_cycle_incoming_exchange_{{ $index }}_select_all_variants' }
|
||||
= t('admin.select_all')
|
||||
{{ 'admin.select_all' | t }}
|
||||
|
||||
.exchange-products
|
||||
-# No need to scope product list based on permissions, because if an incoming exchange is visible,
|
||||
@@ -36,7 +36,7 @@
|
||||
'ofn-sync-distributions' => '{{ product.master_id }}',
|
||||
'id' => 'order_cycle_incoming_exchange_{{ $parent.$index }}_variants_{{ product.master_id }}',
|
||||
'ng-disabled' => '!order_cycle.editable_variants_for_incoming_exchanges.hasOwnProperty(exchange.enterprise_id) || order_cycle.editable_variants_for_incoming_exchanges[exchange.enterprise_id].indexOf(product.master_id) < 0' }
|
||||
= t('admin.obsolete_master')
|
||||
{{ 'admin.obsolete_master' | t }}
|
||||
|
||||
.exchange-product-variant{'ng-repeat' => 'variant in product.variants'}
|
||||
%label
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.row.exchange-tags
|
||||
.sixteen.columns.alpha.omega
|
||||
%span.text-normal
|
||||
= t('admin.tags')
|
||||
{{ 'admin.tags' | t }}
|
||||
%br
|
||||
%tags-with-translation.fullwidth{ object: 'object' }
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#schedule-dialog
|
||||
.text-normal.margin-bottom-30.text-center
|
||||
%span{ ng: { hide: 'schedule.id' } }= t('admin.order_cycles.index.adding_a_new_schedule')
|
||||
%span{ ng: { show: 'schedule.id' } }= t('admin.order_cycles.index.updating_a_schedule')
|
||||
|
||||
%form{ name: 'schedule_form', novalidate: true, ng: { submit: "submit()" }}
|
||||
|
||||
.text-center.margin-bottom-20
|
||||
%input.fullwidth{ type: 'text', name: 'name', required: true, placeholder: t('admin.order_cycles.index.schedule_name_placeholder'), ng: { model: "schedule.name" } }
|
||||
%div{ ng: { show: "submitted && schedule_form.$pristine" } }
|
||||
.error{ ng: { show: "(schedule_form.name.$error.required)" } }
|
||||
= t('admin.order_cycles.index.name_required_error')
|
||||
|
||||
.order-cycles-selector.text-center.margin-bottom-30
|
||||
|
||||
.text-center
|
||||
|
||||
%input.button{ type: 'submit', value: t('admin.order_cycles.index.create_schedule'), ng: { hide: 'schedule.id' } }
|
||||
%input.button{ type: 'submit', value: t('admin.order_cycles.index.update_schedule'), ng: { show: 'schedule.id' } }
|
||||
%span{ ng: { show: 'schedule.id' } } or
|
||||
%input.button.red{ type: 'button', value: t('admin.order_cycles.index.delete_schedule'), ng: { show: 'schedule.id', click: 'delete()'} }
|
||||
or
|
||||
%input.button{ type: 'button', value: t('actions.cancel'), ng: { click: 'close()' } }
|
||||
@@ -3,9 +3,9 @@
|
||||
{{$getDisplayText()}}
|
||||
%span.tag-with-rules{ ng: { if: "data.rules == 1" } }
|
||||
—
|
||||
= t('admin.has_one_rule')
|
||||
{{ 'admin.has_one_rule' | t }}
|
||||
%span.tag-with-rules{ ng: { if: "data.rules > 1" } }
|
||||
—
|
||||
= t('admin.has_n_rules', { num: '{{data.rules}}' })
|
||||
{{ 'admin.has_n_rules' | t:{ num: data.rules } }}
|
||||
%span{ ng: { if: "!data.rules" } }
|
||||
{{$getDisplayText()}}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
%tags-input{ template: 'admin/tag.html',
|
||||
"placeholder" => t('admin.order_cycles.form.add_a_tag'),
|
||||
ng: { model: 'object[tagsAttr]', class: "{'limit-reached': limitReached}"},
|
||||
on: { tag: { added: 'tagAdded()', removed:'tagRemoved()' } } }
|
||||
%auto-complete{ ng: { if: "findTags" }, source: "findTags({query: $query})",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user