Changeset 2670662
- Timestamp:
- 02/01/2022 03:05:45 PM (4 years ago)
- Location:
- shopping-feed
- Files:
-
- 2 added
- 52 edited
- 1 copied
-
tags/6.1.0 (copied) (copied from shopping-feed/trunk)
-
tags/6.1.0/assets/css/app.css (modified) (3 diffs)
-
tags/6.1.0/assets/js/accounts.js (added)
-
tags/6.1.0/assets/scss/main/_sf.scss (modified) (2 diffs)
-
tags/6.1.0/readme.txt (modified) (2 diffs)
-
tags/6.1.0/shoppingfeed.php (modified) (3 diffs)
-
tags/6.1.0/src/Actions/Actions.php (modified) (1 diff)
-
tags/6.1.0/src/Admin/Metabox.php (modified) (1 diff)
-
tags/6.1.0/src/Admin/Notices.php (modified) (1 diff)
-
tags/6.1.0/src/Admin/Options.php (modified) (12 diffs)
-
tags/6.1.0/src/Admin/Requirements.php (modified) (2 diffs)
-
tags/6.1.0/src/Admin/WoocommerceActions.php (modified) (10 diffs)
-
tags/6.1.0/src/Feed/Generator.php (modified) (1 diff)
-
tags/6.1.0/src/Orders/Operations.php (modified) (1 diff)
-
tags/6.1.0/src/Orders/Order.php (modified) (4 diffs)
-
tags/6.1.0/src/Orders/Order/Metas.php (modified) (4 diffs)
-
tags/6.1.0/src/Orders/Orders.php (modified) (2 diffs)
-
tags/6.1.0/src/Products/Product.php (modified) (1 diff)
-
tags/6.1.0/src/Query/Query.php (modified) (2 diffs)
-
tags/6.1.0/src/Sdk/Sdk.php (modified) (4 diffs)
-
tags/6.1.0/src/ShoppingFeed.php (modified) (3 diffs)
-
tags/6.1.0/src/ShoppingFeedHelper.php (modified) (8 diffs)
-
tags/6.1.0/vendor/autoload.php (modified) (1 diff)
-
tags/6.1.0/vendor/composer/ClassLoader.php (modified) (1 diff)
-
tags/6.1.0/vendor/composer/InstalledVersions.php (modified) (1 diff)
-
tags/6.1.0/vendor/composer/autoload_real.php (modified) (5 diffs)
-
tags/6.1.0/vendor/composer/autoload_static.php (modified) (2 diffs)
-
tags/6.1.0/vendor/composer/installed.php (modified) (2 diffs)
-
trunk/assets/css/app.css (modified) (3 diffs)
-
trunk/assets/js/accounts.js (added)
-
trunk/assets/scss/main/_sf.scss (modified) (2 diffs)
-
trunk/readme.txt (modified) (2 diffs)
-
trunk/shoppingfeed.php (modified) (3 diffs)
-
trunk/src/Actions/Actions.php (modified) (1 diff)
-
trunk/src/Admin/Metabox.php (modified) (1 diff)
-
trunk/src/Admin/Notices.php (modified) (1 diff)
-
trunk/src/Admin/Options.php (modified) (12 diffs)
-
trunk/src/Admin/Requirements.php (modified) (2 diffs)
-
trunk/src/Admin/WoocommerceActions.php (modified) (10 diffs)
-
trunk/src/Feed/Generator.php (modified) (1 diff)
-
trunk/src/Orders/Operations.php (modified) (1 diff)
-
trunk/src/Orders/Order.php (modified) (4 diffs)
-
trunk/src/Orders/Order/Metas.php (modified) (4 diffs)
-
trunk/src/Orders/Orders.php (modified) (2 diffs)
-
trunk/src/Products/Product.php (modified) (1 diff)
-
trunk/src/Query/Query.php (modified) (2 diffs)
-
trunk/src/Sdk/Sdk.php (modified) (4 diffs)
-
trunk/src/ShoppingFeed.php (modified) (3 diffs)
-
trunk/src/ShoppingFeedHelper.php (modified) (8 diffs)
-
trunk/vendor/autoload.php (modified) (1 diff)
-
trunk/vendor/composer/ClassLoader.php (modified) (1 diff)
-
trunk/vendor/composer/InstalledVersions.php (modified) (1 diff)
-
trunk/vendor/composer/autoload_real.php (modified) (5 diffs)
-
trunk/vendor/composer/autoload_static.php (modified) (2 diffs)
-
trunk/vendor/composer/installed.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
shopping-feed/tags/6.1.0/assets/css/app.css
r2384546 r2670662 71 71 cursor: inherit; } 72 72 73 .sf__inline { 74 display: inline-block; 75 margin-right: 0; } 76 77 .sf__table tr:first-child button { 78 display: none; } 79 80 .sf__table td { 81 padding-left: 0; } 82 73 83 .sf__logo { 74 84 overflow: hidden; … … 95 105 background-color: #19a088; } 96 106 97 .sf__button__ logout.button {107 .sf__button__secondary.button, .sf__button__logout.button { 98 108 color: #fff; 99 109 text-transform: uppercase; 100 110 border-color: #632F8E; 101 111 background-color: #632F8E; } 102 .sf__button__ logout.button:hover, .sf__button__logout.button:active, .sf__button__logout.button:focus {112 .sf__button__secondary.button:hover, .sf__button__secondary.button:active, .sf__button__secondary.button:focus, .sf__button__logout.button:hover, .sf__button__logout.button:active, .sf__button__logout.button:focus { 103 113 color: #fff; 104 114 border-color: #56297b; … … 222 232 flex-basis: 33%; } } 223 233 224 /*# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBwLmNzcyIsInNvdXJjZXMiOlsiYXBwLnNjc3MiLCJtYWluL19taXhpbnMuc2NzcyIsIm1haW4vX2NvbG9ycy5zY3NzIiwibXVsdGkvX211bHRpLnNjc3MiLCJtYWluL19zZi5zY3NzIl0sInNvdXJjZXNDb250ZW50IjpbIkBpbXBvcnQgXCJtYWluL21peGluc1wiO1xuQGltcG9ydCBcIm1haW4vY29sb3JzXCI7XG5AaW1wb3J0IFwibXVsdGkvbXVsdGlcIjtcbkBpbXBvcnQgXCJtYWluL3NmXCI7IiwiLy8gQm91cmJvbidzIGVzc2VudGlhbHMgbWl4aW5zXG4kZW0tYmFzZTogMTZweCAhZGVmYXVsdDtcbi8vIFN0cmlwIHVuaXRzXG5AZnVuY3Rpb24gc3RyaXAtdW5pdHMoJHZhbHVlKSB7XG5cdEByZXR1cm4gKCR2YWx1ZSAvICgkdmFsdWUgKiAwICsgMSkpO1xufVxuLy8gUFggdG8gRU1cbkBmdW5jdGlvbiBlbSgkcHh2YWwsICRiYXNlOiAkZW0tYmFzZSkge1xuXHRAaWYgbm90IHVuaXRsZXNzKCRweHZhbCkge1xuXHQgICRweHZhbDogc3RyaXAtdW5pdHMoJHB4dmFsKTtcblx0fVxuXHRAaWYgbm90IHVuaXRsZXNzKCRiYXNlKSB7XG5cdCAgJGJhc2U6IHN0cmlwLXVuaXRzKCRiYXNlKTtcblx0fVxuXHRAcmV0dXJuICgkcHh2YWwgLyAkYmFzZSkgKiAxZW07XG59XG4vL0JyZWFrcG9pbnRzXG4kYnJlYWtwb2ludHM6IChcbiAgICB4c206IGVtKDQ4MCksXG4gICAgc206IGVtKDc2OCksXG4gICAgbWQ6IGVtKDEwMjQpLFxuICAgIGxnOiBlbSgxMjYwKSxcbiAgICB4bGc6IGVtKDE0NDApXG4pO1xuXG5AbWl4aW4gYnJlYWtwb2ludHMoJGJyZWFrcG9pbnQpIHtcbiAgICBAbWVkaWEgc2NyZWVuIGFuZCAobWluLXdpZHRoOiBtYXAtZ2V0KCRtYXA6ICRicmVha3BvaW50cywgJGtleTogJGJyZWFrcG9pbnQpKSB7XG4gICAgICAgIEBjb250ZW50O1xuICAgIH1cbn1cbi8vIEhvdmVyIEFjdGl2ZSBGb2N1cyBwc2V1ZG8gc2VsZWN0b3IgbWl4aW5cbkBtaXhpbiBob3ZlciB7XG5cdCY6aG92ZXIsICY6YWN0aXZlLCAmOmZvY3VzIHtcblx0XHRAY29udGVudDtcblx0fVxufVxuLy8gU21vb3RoIHRleHRcbkBtaXhpbiBzbW9vdGhUZXh0IHtcblx0LXdlYmtpdC1mb250LXNtb290aGluZzogYW50aWFsaWFzZWQ7XG4gICAgLW1vei1vc3gtZm9udC1zbW9vdGhpbmc6IGdyYXlzY2FsZTtcbn0iLCIkd2hpdGU6ICNmZmY7XG4kYmxhY2s6ICMwMDA7XG4kcHJpbWFyeTogIzYzMkY4RTtcbiRzZWNvbmRhcnk6ICMxQ0I2OUI7XG4kdGV4dGNvbG9yOiAjMjMyODJEO1xuJGdyYXk6ICM5RTlFOUU7XG4kYmx1ZTogIzA0Mjc0RDtcbiRwaW5rOiAjRTkxRTYzO1xuIiwiLm11bHRpLXdyYXBwZXIge1xuICAgIGJvcmRlcjogMXB4IHNvbGlkICNjY2M7XG4gICAgYm9yZGVyLXJhZGl1czogM3B4O1xuICAgIHdpZHRoOiAxMDAlO1xufVxuXG4ubXVsdGktd3JhcHBlciAubm9uLXNlbGVjdGVkLXdyYXBwZXIsXG4ubXVsdGktd3JhcHBlciAuc2VsZWN0ZWQtd3JhcHBlciB7XG4gICAgYm94LXNpemluZzogYm9yZGVyLWJveDtcbiAgICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7XG4gICAgaGVpZ2h0OiAyMDBweDtcbiAgICBvdmVyZmxvdy15OiBzY3JvbGw7XG4gICAgcGFkZGluZzogMTBweDtcbiAgICB2ZXJ0aWNhbC1hbGlnbjogdG9wO1xuICAgIHdpZHRoOiA1MCU7XG59XG5cbi5tdWx0aS13cmFwcGVyIC5ub24tc2VsZWN0ZWQtd3JhcHBlciB7XG4gICAgYmFja2dyb3VuZDogI2ZhZmFmYTtcbiAgICBib3JkZXItcmlnaHQ6IDFweCBzb2xpZCAjY2NjO1xufVxuXG4ubXVsdGktd3JhcHBlciAuc2VsZWN0ZWQtd3JhcHBlciB7XG4gICAgYmFja2dyb3VuZDogI2ZmZjtcbn1cblxuLm11bHRpLXdyYXBwZXIgLmhlYWRlciB7XG4gICAgY29sb3I6ICM0ZjRmNGY7XG4gICAgY3Vyc29yOiBkZWZhdWx0O1xuICAgIGZvbnQtd2VpZ2h0OiBib2xkO1xuICAgIG1hcmdpbi1ib3R0b206IDVweDtcbiAgICBwYWRkaW5nOiA1cHggMTBweDtcbn1cblxuLm11bHRpLXdyYXBwZXIgLml0ZW0ge1xuICAgIGN1cnNvcjogcG9pbnRlcjtcbiAgICBkaXNwbGF5OiBibG9jaztcbiAgICBwYWRkaW5nOiA1cHggMTBweDtcbn1cblxuLm11bHRpLXdyYXBwZXIgLml0ZW06aG92ZXIge1xuICAgIGJhY2tncm91bmQ6ICNlY2VjZWM7XG4gICAgYm9yZGVyLXJhZGl1czogMnB4O1xufVxuXG4ubXVsdGktd3JhcHBlciAuaXRlbS1ncm91cCB7XG4gICAgcGFkZGluZzogNXB4IDEwcHg7XG59XG5cbi5tdWx0aS13cmFwcGVyIC5pdGVtLWdyb3VwIC5ncm91cC1sYWJlbCB7XG4gICAgZGlzcGxheTogYmxvY2s7XG4gICAgZm9udC1zaXplOiAwLjg3NXJlbTtcbiAgICBvcGFjaXR5OiAwLjU7XG4gICAgcGFkZGluZzogNXB4IDA7XG59XG5cbi5tdWx0aS13cmFwcGVyIC5zZWFyY2gtaW5wdXQge1xuICAgIGJvcmRlcjogMDtcbiAgICBib3JkZXItYm90dG9tOiAxcHggc29saWQgI2NjYztcbiAgICBib3JkZXItcmFkaXVzOiAwO1xuICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgIGZvbnQtc2l6ZTogMWVtO1xuICAgIG1hcmdpbjogMDtcbiAgICBvdXRsaW5lOiAwO1xuICAgIHBhZGRpbmc6IDEwcHggMjBweDtcbiAgICB3aWR0aDogMTAwJTtcbiAgICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xufVxuXG4ubXVsdGktd3JhcHBlciAubm9uLXNlbGVjdGVkLXdyYXBwZXIgLml0ZW0uc2VsZWN0ZWQge1xuICAgIG9wYWNpdHk6IDAuNTtcbn1cblxuLm11bHRpLXdyYXBwZXIgLm5vbi1zZWxlY3RlZC13cmFwcGVyIC5pdGVtLmRpc2FibGVkLFxuLm11bHRpLXdyYXBwZXIgLnNlbGVjdGVkLXdyYXBwZXIgLml0ZW0uZGlzYWJsZWQge1xuICAgIG9wYWNpdHk6IDAuNTtcbiAgICB0ZXh0LWRlY29yYXRpb246IGxpbmUtdGhyb3VnaDtcbn1cblxuLm11bHRpLXdyYXBwZXIgLm5vbi1zZWxlY3RlZC13cmFwcGVyIC5pdGVtLmRpc2FibGVkOmhvdmVyLFxuLm11bHRpLXdyYXBwZXIgLnNlbGVjdGVkLXdyYXBwZXIgLml0ZW0uZGlzYWJsZWQ6aG92ZXIge1xuICAgIGJhY2tncm91bmQ6IGluaGVyaXQ7XG4gICAgY3Vyc29yOiBpbmhlcml0O1xufSIsIi5zZiB7XG5cbiAgJl9f bG9nbyB7XG4gICAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgICB0ZXh0LWluZGVudDogLTk5OTk5cHg7XG4gICAgYmFja2dyb3VuZDogdXJsKFwiLi4vaW1hZ2VzL3NmX2xvZ28uc3ZnXCIpIG5vLXJlcGVhdCBjZW50ZXIgbGVmdDtcbiAgICBiYWNrZ3JvdW5kLXNpemU6IGNvbnRhaW47XG4gICAgbWF4LXdpZHRoOiAyOTdweDtcbiAgICBoZWlnaHQ6IDUzcHg7XG4gIH1cblxuICAmX192ZXJzaW9uIHtcbiAgICBjb2xvcjogJGdyYXk7XG4gICAgZm9udC1zaXplOiAxMnB4O1xuICAgIGxpbmUtaGVpZ2h0OiAxN3B4O1xuICAgIG1hcmdpbjogNXB4IDA7XG4gIH1cblxuICAmX19idXR0b24uYnV0dG9uIHtcbiAgICBjb2xvcjogJHdoaXRlO1xuICAgIHRleHQtdHJhbnNmb3JtOiB1cHBlcmNhc2U7XG4gICAgYm9yZGVyLWNvbG9yOiAkc2Vjb25kYXJ5O1xuICAgIGJhY2tncm91bmQtY29sb3I6ICRzZWNvbmRhcnk7XG4gICAgQGluY2x1ZGUgaG92ZXIge1xuICAgICAgY29sb3I6ICR3aGl0ZTtcbiAgICAgIGJvcmRlci1jb2xvcjogZGFya2VuKCRzZWNvbmRhcnksIDUlKTtcbiAgICAgIGJhY2tncm91bmQtY29sb3I6IGRhcmtlbigkc2Vjb25kYXJ5LCA1JSk7XG4gICAgfVxuICB9XG5cbiAgJl9fYnV0dG9uX19sb2dvdXQuYnV0dG9uIHtcbiAgICBjb2xvcjogJHdoaXRlO1xuICAgIHRleHQtdHJhbnNmb3JtOiB1cHBlcmNhc2U7XG4gICAgYm9yZGVyLWNvbG9yOiAkcHJpbWFyeTtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAkcHJpbWFyeTtcbiAgICBAaW5jbHVkZSBob3ZlciB7XG4gICAgICBjb2xvcjogJHdoaXRlO1xuICAgICAgYm9yZGVyLWNvbG9yOiBkYXJrZW4oJHByaW1hcnksIDUlKTtcbiAgICAgIGJhY2tncm91bmQtY29sb3I6IGRhcmtlbigkcHJpbWFyeSwgNSUpO1xuICAgIH1cbiAgfVxuXG4gICZfX3JlcXVpcmVtZW50cyB7XG4gICAgLnN1Y2Nlc3MsXG4gICAgLmZhaWxlZCB7XG4gICAgICBAaW5jbHVkZSBzbW9vdGhUZXh0O1xuICAgICAgcG9zaXRpb246IHJlbGF0aXZlO1xuICAgICAgcGFkZGluZy1sZWZ0OiAyNnB4O1xuICAgICAgY29sb3I6ICR0ZXh0Y29sb3I7XG5cbiAgICAgICY6YmVmb3JlIHtcbiAgICAgICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgICAgICB0b3A6IDA7XG4gICAgICAgIGxlZnQ6IDA7XG4gICAgICAgIGZvbnQtZmFtaWx5OiBkYXNoaWNvbnM7XG4gICAgICAgIGNvbnRlbnQ6IFwiXFxmMTQ3XCI7XG4gICAgICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgICAgICB3aWR0aDogMTZweDtcbiAgICAgICAgaGVpZ2h0OiAxNnB4O1xuICAgICAgICBsaW5lLWhlaWdodDogMTZweDtcbiAgICAgICAgZm9udC1zaXplOiAxNHB4O1xuICAgICAgICBib3JkZXItcmFkaXVzOiA1MCU7XG4gICAgICAgIHRleHQtYWxpZ246IGNlbnRlcjtcbiAgICAgICAgY29sb3I6ICR3aGl0ZTtcbiAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogJHNlY29uZGFyeTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAuZmFpbGVkIHtcbiAgICAgIGNvbG9yOiAkdGV4dGNvbG9yO1xuXG4gICAgICAmOmJlZm9yZSB7XG4gICAgICAgIGNvbnRlbnQ6IFwiXFxmMzM1XCI7XG4gICAgICAgIGJhY2tncm91bmQtY29sb3I6ICRncmF5O1xuICAgICAgfVxuICAgIH1cblxuICB9XG5cbiAgJl9faGVybyB7XG4gICAgcG9zaXRpb246IHJlbGF0aXZlO1xuICAgIGJvcmRlcjogMDtcbiAgICBib3JkZXItcmFkaXVzOiAycHg7XG4gICAgYmFja2dyb3VuZDogbGluZWFyLWdyYWRpZW50KDE4MGRlZywgIzAzMjc0RCAwJSwgIzUyMzA4MSAxMDAlKTtcbiAgICBiYWNrZ3JvdW5kLXNpemU6IGNvdmVyO1xuICAgIHBhZGRpbmc6IDMwcHg7XG5cbiAgICAmOmJlZm9yZSB7XG4gICAgICBjb250ZW50OiBcIlwiO1xuICAgICAgZGlzcGxheTogYmxvY2s7XG4gICAgICB6LWluZGV4OiAxO1xuICAgICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgICAgdG9wOiAwO1xuICAgICAgcmlnaHQ6IDMwcHg7XG4gICAgICBib3R0b206IDA7XG4gICAgICBsZWZ0OiAwO1xuICAgICAgYmFja2dyb3VuZDogdXJsKFwiLi4vaW1hZ2VzL3NmX21hcmtldGluZy5zdmdcIikgbm8tcmVwZWF0IGNlbnRlciByaWdodDtcbiAgICAgIHBvaW50ZXItZXZlbnRzOiBub25lO1xuICAgIH1cbiAgICAmLS10aXRsZXtcbiAgICAgIGZvbnQtc2l6ZTogMTZweDtcbiAgICAgIGxpbmUtaGVpZ2h0OiAyMnB4O1xuICAgICAgcGFkZGluZy1yaWdodDogMzBweDtcbiAgICAgIGNvbG9yOiAkd2hpdGU7XG4gICAgICBmb250LXdlaWdodDogYm9sZDtcbiAgICAgIG1hcmdpbi1ib3R0b206IDE1cHg7XG4gICAgfVxuICB9XG5cbiAgJl9fbWFya2V0aW5nIHtcbiAgICBib3JkZXItbGVmdDogMXB4IHNvbGlkICRwcmltYXJ5O1xuICAgIHBhZGRpbmctbGVmdDogMjZweDtcblxuICAgICYtLXRpdGxle1xuICAgICAgY29sb3I6ICRwcmltYXJ5O1xuICAgICAgZm9udC1zaXplOiAxLjVlbTtcbiAgICAgIG1hcmdpbjogMDtcbiAgICAgIG1hcmdpbi10b3A6IDFlbTtcbiAgICB9XG4gICAgJi0tc3VidGl0bGV7XG4gICAgICBjb2xvcjogJGdyYXk7XG4gICAgICBmb250LXNpemU6IDEwcHg7XG4gICAgICB0ZXh0LXRyYW5zZm9ybTogdXBwZXJjYXNlO1xuICAgICAgbGV0dGVyLXNwYWNpbmc6IDMuMzNweDtcbiAgICAgIG1hcmdpbjogMDtcbiAgICAgIHBhZGRpbmctdG9wOiA1cHg7XG4gICAgfVxuICAgICYtLXRleHR7XG4gICAgICBjb2xvcjogJHRleHRjb2xvcjtcbiAgICAgIGZvbnQtc2l6ZTogMTJweDtcbiAgICAgIGxldHRlci1zcGFjaW5nOiAwO1xuICAgICAgbGluZS1oZWlnaHQ6IDE3cHg7XG4gICAgfVxuXG4gICAgJi0tZG93bmxvYWQge1xuICAgICAgcGFkZGluZzogMWVtIDA7XG5cbiAgICAgIGxpIHtcbiAgICAgICAgbGluZS1oZWlnaHQ6IDEuNWVtO1xuICAgICAgfVxuXG4gICAgICBhIHtcbiAgICAgICAgQGluY2x1ZGUgc21vb3RoVGV4dDtcbiAgICAgICAgcG9zaXRpb246IHJlbGF0aXZlO1xuICAgICAgICBwYWRkaW5nLWxlZnQ6IDI2cHg7XG4gICAgICAgIGNvbG9yOiAkYmx1ZTtcbiAgICAgICAgZm9udC13ZWlnaHQ6IGJvbGQ7XG5cbiAgICAgICAgJjpiZWZvcmUge1xuICAgICAgICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICAgICAgICB0b3A6IDA7XG4gICAgICAgICAgbGVmdDogMDtcbiAgICAgICAgICBmb250LWZhbWlseTogZGFzaGljb25zO1xuICAgICAgICAgIGNvbnRlbnQ6IFwiXFxmMzQ2XCI7XG4gICAgICAgICAgZGlzcGxheTogYmxvY2s7XG4gICAgICAgICAgd2lkdGg6IDE2cHg7XG4gICAgICAgICAgaGVpZ2h0OiAxNnB4O1xuICAgICAgICAgIGxpbmUtaGVpZ2h0OiAxNnB4O1xuICAgICAgICAgIGZvbnQtc2l6ZTogMTRweDtcbiAgICAgICAgICBib3JkZXItcmFkaXVzOiA1MCU7XG4gICAgICAgICAgdGV4dC1hbGlnbjogY2VudGVyO1xuICAgICAgICAgIGNvbG9yOiAkd2hpdGU7XG4gICAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogJHByaW1hcnk7XG4gICAgICAgIH1cblxuICAgICAgICAmOmhvdmVyIHtcbiAgICAgICAgICBjb2xvcjogJHByaW1hcnk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAmX19wbHVnaW57XG4gICAgLnNmX19ub3RpY2UtLXN0YXJ0IGF7XG4gICAgICBkaXNwbGF5OiBub25lO1xuICAgIH1cbiAgfVxuXG5cbiAgQGluY2x1ZGUgYnJlYWtwb2ludHMobWQpIHtcbiAgICAmX19jb2x1bW5zIHtcbiAgICAgIGRpc3BsYXk6IGZsZXg7XG4gICAgICBmbGV4LXdyYXA6IHdyYXA7XG4gICAgfVxuICAgICZfX2NvbHVtbiB7XG4gICAgICBmbGV4LWJhc2lzOiA2NiU7XG5cbiAgICAgICY6bGFzdC1jaGlsZCB7XG4gICAgICAgIGZsZXgtYmFzaXM6IDMzJTtcbiAgICAgIH1cbiAgICB9XG5cbiAgfVxufVxuIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBR0FBLEFBQUEsY0FBYyxDQUFDO0VBQ1gsTUFBTSxFQUFFLGNBQWM7RUFDdEIsYUFBYSxFQUFFLEdBQUc7RUFDbEIsS0FBSyxFQUFFLElBQUksR0FDZDs7QUFFRCxBQUFBLGNBQWMsQ0FBQyxxQkFBcUI7QUFDcEMsY0FBYyxDQUFDLGlCQUFpQixDQUFDO0VBQzdCLFVBQVUsRUFBRSxVQUFVO0VBQ3RCLE9BQU8sRUFBRSxZQUFZO0VBQ3JCLE1BQU0sRUFBRSxLQUFLO0VBQ2IsVUFBVSxFQUFFLE1BQU07RUFDbEIsT0FBTyxFQUFFLElBQUk7RUFDYixjQUFjLEVBQUUsR0FBRztFQUNuQixLQUFLLEVBQUUsR0FBRyxHQUNiOztBQUVELEFBQUEsY0FBYyxDQUFDLHFCQUFxQixDQUFDO0VBQ2pDLFVBQVUsRUFBRSxPQUFPO0VBQ25CLFlBQVksRUFBRSxjQUFjLEdBQy9COztBQUVELEFBQUEsY0FBYyxDQUFDLGlCQUFpQixDQUFDO0VBQzdCLFVBQVUsRUFBRSxJQUFJLEdBQ25COztBQUVELEFBQUEsY0FBYyxDQUFDLE9BQU8sQ0FBQztFQUNuQixLQUFLLEVBQUUsT0FBTztFQUNkLE1BQU0sRUFBRSxPQUFPO0VBQ2YsV0FBVyxFQUFFLElBQUk7RUFDakIsYUFBYSxFQUFFLEdBQUc7RUFDbEIsT0FBTyxFQUFFLFFBQVEsR0FDcEI7O0FBRUQsQUFBQSxjQUFjLENBQUMsS0FBSyxDQUFDO0VBQ2pCLE1BQU0sRUFBRSxPQUFP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*/234 /*# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBwLmNzcyIsInNvdXJjZXMiOlsiYXBwLnNjc3MiLCJtYWluL19taXhpbnMuc2NzcyIsIm1haW4vX2NvbG9ycy5zY3NzIiwibXVsdGkvX211bHRpLnNjc3MiLCJtYWluL19zZi5zY3NzIl0sInNvdXJjZXNDb250ZW50IjpbIkBpbXBvcnQgXCJtYWluL21peGluc1wiO1xuQGltcG9ydCBcIm1haW4vY29sb3JzXCI7XG5AaW1wb3J0IFwibXVsdGkvbXVsdGlcIjtcbkBpbXBvcnQgXCJtYWluL3NmXCI7IiwiLy8gQm91cmJvbidzIGVzc2VudGlhbHMgbWl4aW5zXG4kZW0tYmFzZTogMTZweCAhZGVmYXVsdDtcbi8vIFN0cmlwIHVuaXRzXG5AZnVuY3Rpb24gc3RyaXAtdW5pdHMoJHZhbHVlKSB7XG5cdEByZXR1cm4gKCR2YWx1ZSAvICgkdmFsdWUgKiAwICsgMSkpO1xufVxuLy8gUFggdG8gRU1cbkBmdW5jdGlvbiBlbSgkcHh2YWwsICRiYXNlOiAkZW0tYmFzZSkge1xuXHRAaWYgbm90IHVuaXRsZXNzKCRweHZhbCkge1xuXHQgICRweHZhbDogc3RyaXAtdW5pdHMoJHB4dmFsKTtcblx0fVxuXHRAaWYgbm90IHVuaXRsZXNzKCRiYXNlKSB7XG5cdCAgJGJhc2U6IHN0cmlwLXVuaXRzKCRiYXNlKTtcblx0fVxuXHRAcmV0dXJuICgkcHh2YWwgLyAkYmFzZSkgKiAxZW07XG59XG4vL0JyZWFrcG9pbnRzXG4kYnJlYWtwb2ludHM6IChcbiAgICB4c206IGVtKDQ4MCksXG4gICAgc206IGVtKDc2OCksXG4gICAgbWQ6IGVtKDEwMjQpLFxuICAgIGxnOiBlbSgxMjYwKSxcbiAgICB4bGc6IGVtKDE0NDApXG4pO1xuXG5AbWl4aW4gYnJlYWtwb2ludHMoJGJyZWFrcG9pbnQpIHtcbiAgICBAbWVkaWEgc2NyZWVuIGFuZCAobWluLXdpZHRoOiBtYXAtZ2V0KCRtYXA6ICRicmVha3BvaW50cywgJGtleTogJGJyZWFrcG9pbnQpKSB7XG4gICAgICAgIEBjb250ZW50O1xuICAgIH1cbn1cbi8vIEhvdmVyIEFjdGl2ZSBGb2N1cyBwc2V1ZG8gc2VsZWN0b3IgbWl4aW5cbkBtaXhpbiBob3ZlciB7XG5cdCY6aG92ZXIsICY6YWN0aXZlLCAmOmZvY3VzIHtcblx0XHRAY29udGVudDtcblx0fVxufVxuLy8gU21vb3RoIHRleHRcbkBtaXhpbiBzbW9vdGhUZXh0IHtcblx0LXdlYmtpdC1mb250LXNtb290aGluZzogYW50aWFsaWFzZWQ7XG4gICAgLW1vei1vc3gtZm9udC1zbW9vdGhpbmc6IGdyYXlzY2FsZTtcbn0iLCIkd2hpdGU6ICNmZmY7XG4kYmxhY2s6ICMwMDA7XG4kcHJpbWFyeTogIzYzMkY4RTtcbiRzZWNvbmRhcnk6ICMxQ0I2OUI7XG4kdGV4dGNvbG9yOiAjMjMyODJEO1xuJGdyYXk6ICM5RTlFOUU7XG4kYmx1ZTogIzA0Mjc0RDtcbiRwaW5rOiAjRTkxRTYzO1xuIiwiLm11bHRpLXdyYXBwZXIge1xuICAgIGJvcmRlcjogMXB4IHNvbGlkICNjY2M7XG4gICAgYm9yZGVyLXJhZGl1czogM3B4O1xuICAgIHdpZHRoOiAxMDAlO1xufVxuXG4ubXVsdGktd3JhcHBlciAubm9uLXNlbGVjdGVkLXdyYXBwZXIsXG4ubXVsdGktd3JhcHBlciAuc2VsZWN0ZWQtd3JhcHBlciB7XG4gICAgYm94LXNpemluZzogYm9yZGVyLWJveDtcbiAgICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7XG4gICAgaGVpZ2h0OiAyMDBweDtcbiAgICBvdmVyZmxvdy15OiBzY3JvbGw7XG4gICAgcGFkZGluZzogMTBweDtcbiAgICB2ZXJ0aWNhbC1hbGlnbjogdG9wO1xuICAgIHdpZHRoOiA1MCU7XG59XG5cbi5tdWx0aS13cmFwcGVyIC5ub24tc2VsZWN0ZWQtd3JhcHBlciB7XG4gICAgYmFja2dyb3VuZDogI2ZhZmFmYTtcbiAgICBib3JkZXItcmlnaHQ6IDFweCBzb2xpZCAjY2NjO1xufVxuXG4ubXVsdGktd3JhcHBlciAuc2VsZWN0ZWQtd3JhcHBlciB7XG4gICAgYmFja2dyb3VuZDogI2ZmZjtcbn1cblxuLm11bHRpLXdyYXBwZXIgLmhlYWRlciB7XG4gICAgY29sb3I6ICM0ZjRmNGY7XG4gICAgY3Vyc29yOiBkZWZhdWx0O1xuICAgIGZvbnQtd2VpZ2h0OiBib2xkO1xuICAgIG1hcmdpbi1ib3R0b206IDVweDtcbiAgICBwYWRkaW5nOiA1cHggMTBweDtcbn1cblxuLm11bHRpLXdyYXBwZXIgLml0ZW0ge1xuICAgIGN1cnNvcjogcG9pbnRlcjtcbiAgICBkaXNwbGF5OiBibG9jaztcbiAgICBwYWRkaW5nOiA1cHggMTBweDtcbn1cblxuLm11bHRpLXdyYXBwZXIgLml0ZW06aG92ZXIge1xuICAgIGJhY2tncm91bmQ6ICNlY2VjZWM7XG4gICAgYm9yZGVyLXJhZGl1czogMnB4O1xufVxuXG4ubXVsdGktd3JhcHBlciAuaXRlbS1ncm91cCB7XG4gICAgcGFkZGluZzogNXB4IDEwcHg7XG59XG5cbi5tdWx0aS13cmFwcGVyIC5pdGVtLWdyb3VwIC5ncm91cC1sYWJlbCB7XG4gICAgZGlzcGxheTogYmxvY2s7XG4gICAgZm9udC1zaXplOiAwLjg3NXJlbTtcbiAgICBvcGFjaXR5OiAwLjU7XG4gICAgcGFkZGluZzogNXB4IDA7XG59XG5cbi5tdWx0aS13cmFwcGVyIC5zZWFyY2gtaW5wdXQge1xuICAgIGJvcmRlcjogMDtcbiAgICBib3JkZXItYm90dG9tOiAxcHggc29saWQgI2NjYztcbiAgICBib3JkZXItcmFkaXVzOiAwO1xuICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgIGZvbnQtc2l6ZTogMWVtO1xuICAgIG1hcmdpbjogMDtcbiAgICBvdXRsaW5lOiAwO1xuICAgIHBhZGRpbmc6IDEwcHggMjBweDtcbiAgICB3aWR0aDogMTAwJTtcbiAgICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xufVxuXG4ubXVsdGktd3JhcHBlciAubm9uLXNlbGVjdGVkLXdyYXBwZXIgLml0ZW0uc2VsZWN0ZWQge1xuICAgIG9wYWNpdHk6IDAuNTtcbn1cblxuLm11bHRpLXdyYXBwZXIgLm5vbi1zZWxlY3RlZC13cmFwcGVyIC5pdGVtLmRpc2FibGVkLFxuLm11bHRpLXdyYXBwZXIgLnNlbGVjdGVkLXdyYXBwZXIgLml0ZW0uZGlzYWJsZWQge1xuICAgIG9wYWNpdHk6IDAuNTtcbiAgICB0ZXh0LWRlY29yYXRpb246IGxpbmUtdGhyb3VnaDtcbn1cblxuLm11bHRpLXdyYXBwZXIgLm5vbi1zZWxlY3RlZC13cmFwcGVyIC5pdGVtLmRpc2FibGVkOmhvdmVyLFxuLm11bHRpLXdyYXBwZXIgLnNlbGVjdGVkLXdyYXBwZXIgLml0ZW0uZGlzYWJsZWQ6aG92ZXIge1xuICAgIGJhY2tncm91bmQ6IGluaGVyaXQ7XG4gICAgY3Vyc29yOiBpbmhlcml0O1xufSIsIi5zZiB7XG5cbiAgJl9faW5saW5le1xuICAgIGRpc3BsYXk6IGlubGluZS1ibG9jaztcbiAgICBtYXJnaW4tcmlnaHQ6IDA7XG4gIH1cblxuICAmX190YWJsZSB7XG4gICAgdHI6Zmlyc3QtY2hpbGQgYnV0dG9ue1xuICAgICAgZGlzcGxheTogbm9uZTtcbiAgICB9XG4gICAgdGQge1xuICAgICAgcGFkZGluZy1sZWZ0OiAwO1xuICAgIH1cbiAgfVxuXG4gICZfX2xvZ28ge1xuICAgIG92ZXJmbG93OiBoaWRkZW47XG4gICAgdGV4dC1pbmRlbnQ6IC05OTk5OXB4O1xuICAgIGJhY2tncm91bmQ6IHVybChcIi4uL2ltYWdlcy9zZl9sb2dvLnN2Z1wiKSBuby1yZXBlYXQgY2VudGVyIGxlZnQ7XG4gICAgYmFja2dyb3VuZC1zaXplOiBjb250YWluO1xuICAgIG1heC13aWR0aDogMjk3cHg7XG4gICAgaGVpZ2h0OiA1M3B4O1xuICB9XG5cbiAgJl9fdmVyc2lvbiB7XG4gICAgY29sb3I6ICRncmF5O1xuICAgIGZvbnQtc2l6ZTogMTJweDtcbiAgICBsaW5lLWhlaWdodDogMTdweDtcbiAgICBtYXJnaW46IDVweCAwO1xuICB9XG5cbiAgJl9fYnV0dG9uLmJ1dHRvbiB7XG4gICAgY29sb3I6ICR3aGl0ZTtcbiAgICB0ZXh0LXRyYW5zZm9ybTogdXBwZXJjYXNlO1xuICAgIGJvcmRlci1jb2xvcjogJHNlY29uZGFyeTtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAkc2Vjb25kYXJ5O1xuICAgIEBpbmNsdWRlIGhvdmVyIHtcbiAgICAgIGNvbG9yOiAkd2hpdGU7XG4gICAgICBib3JkZXItY29sb3I6IGRhcmtlbigkc2Vjb25kYXJ5LCA1JSk7XG4gICAgICBiYWNrZ3JvdW5kLWNvbG9yOiBkYXJrZW4oJHNlY29uZGFyeSwgNSUpO1xuICAgIH1cbiAgfVxuXG4gICZfX2J1dHRvbl9fc2Vjb25kYXJ5LmJ1dHRvbixcbiAgJl9fYnV0dG9uX19sb2dvdXQuYnV0dG9uIHtcbiAgICBjb2xvcjogJHdoaXRlO1xuICAgIHRleHQtdHJhbnNmb3JtOiB1cHBlcmNhc2U7XG4gICAgYm9yZGVyLWNvbG9yOiAkcHJpbWFyeTtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAkcHJpbWFyeTtcbiAgICBAaW5jbHVkZSBob3ZlciB7XG4gICAgICBjb2xvcjogJHdoaXRlO1xuICAgICAgYm9yZGVyLWNvbG9yOiBkYXJrZW4oJHByaW1hcnksIDUlKTtcbiAgICAgIGJhY2tncm91bmQtY29sb3I6IGRhcmtlbigkcHJpbWFyeSwgNSUpO1xuICAgIH1cbiAgfVxuXG4gICZfX3JlcXVpcmVtZW50cyB7XG4gICAgLnN1Y2Nlc3MsXG4gICAgLmZhaWxlZCB7XG4gICAgICBAaW5jbHVkZSBzbW9vdGhUZXh0O1xuICAgICAgcG9zaXRpb246IHJlbGF0aXZlO1xuICAgICAgcGFkZGluZy1sZWZ0OiAyNnB4O1xuICAgICAgY29sb3I6ICR0ZXh0Y29sb3I7XG5cbiAgICAgICY6YmVmb3JlIHtcbiAgICAgICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgICAgICB0b3A6IDA7XG4gICAgICAgIGxlZnQ6IDA7XG4gICAgICAgIGZvbnQtZmFtaWx5OiBkYXNoaWNvbnM7XG4gICAgICAgIGNvbnRlbnQ6IFwiXFxmMTQ3XCI7XG4gICAgICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgICAgICB3aWR0aDogMTZweDtcbiAgICAgICAgaGVpZ2h0OiAxNnB4O1xuICAgICAgICBsaW5lLWhlaWdodDogMTZweDtcbiAgICAgICAgZm9udC1zaXplOiAxNHB4O1xuICAgICAgICBib3JkZXItcmFkaXVzOiA1MCU7XG4gICAgICAgIHRleHQtYWxpZ246IGNlbnRlcjtcbiAgICAgICAgY29sb3I6ICR3aGl0ZTtcbiAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogJHNlY29uZGFyeTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAuZmFpbGVkIHtcbiAgICAgIGNvbG9yOiAkdGV4dGNvbG9yO1xuXG4gICAgICAmOmJlZm9yZSB7XG4gICAgICAgIGNvbnRlbnQ6IFwiXFxmMzM1XCI7XG4gICAgICAgIGJhY2tncm91bmQtY29sb3I6ICRncmF5O1xuICAgICAgfVxuICAgIH1cblxuICB9XG5cbiAgJl9faGVybyB7XG4gICAgcG9zaXRpb246IHJlbGF0aXZlO1xuICAgIGJvcmRlcjogMDtcbiAgICBib3JkZXItcmFkaXVzOiAycHg7XG4gICAgYmFja2dyb3VuZDogbGluZWFyLWdyYWRpZW50KDE4MGRlZywgIzAzMjc0RCAwJSwgIzUyMzA4MSAxMDAlKTtcbiAgICBiYWNrZ3JvdW5kLXNpemU6IGNvdmVyO1xuICAgIHBhZGRpbmc6IDMwcHg7XG5cbiAgICAmOmJlZm9yZSB7XG4gICAgICBjb250ZW50OiBcIlwiO1xuICAgICAgZGlzcGxheTogYmxvY2s7XG4gICAgICB6LWluZGV4OiAxO1xuICAgICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgICAgdG9wOiAwO1xuICAgICAgcmlnaHQ6IDMwcHg7XG4gICAgICBib3R0b206IDA7XG4gICAgICBsZWZ0OiAwO1xuICAgICAgYmFja2dyb3VuZDogdXJsKFwiLi4vaW1hZ2VzL3NmX21hcmtldGluZy5zdmdcIikgbm8tcmVwZWF0IGNlbnRlciByaWdodDtcbiAgICAgIHBvaW50ZXItZXZlbnRzOiBub25lO1xuICAgIH1cbiAgICAmLS10aXRsZXtcbiAgICAgIGZvbnQtc2l6ZTogMTZweDtcbiAgICAgIGxpbmUtaGVpZ2h0OiAyMnB4O1xuICAgICAgcGFkZGluZy1yaWdodDogMzBweDtcbiAgICAgIGNvbG9yOiAkd2hpdGU7XG4gICAgICBmb250LXdlaWdodDogYm9sZDtcbiAgICAgIG1hcmdpbi1ib3R0b206IDE1cHg7XG4gICAgfVxuICB9XG5cbiAgJl9fbWFya2V0aW5nIHtcbiAgICBib3JkZXItbGVmdDogMXB4IHNvbGlkICRwcmltYXJ5O1xuICAgIHBhZGRpbmctbGVmdDogMjZweDtcblxuICAgICYtLXRpdGxle1xuICAgICAgY29sb3I6ICRwcmltYXJ5O1xuICAgICAgZm9udC1zaXplOiAxLjVlbTtcbiAgICAgIG1hcmdpbjogMDtcbiAgICAgIG1hcmdpbi10b3A6IDFlbTtcbiAgICB9XG4gICAgJi0tc3VidGl0bGV7XG4gICAgICBjb2xvcjogJGdyYXk7XG4gICAgICBmb250LXNpemU6IDEwcHg7XG4gICAgICB0ZXh0LXRyYW5zZm9ybTogdXBwZXJjYXNlO1xuICAgICAgbGV0dGVyLXNwYWNpbmc6IDMuMzNweDtcbiAgICAgIG1hcmdpbjogMDtcbiAgICAgIHBhZGRpbmctdG9wOiA1cHg7XG4gICAgfVxuICAgICYtLXRleHR7XG4gICAgICBjb2xvcjogJHRleHRjb2xvcjtcbiAgICAgIGZvbnQtc2l6ZTogMTJweDtcbiAgICAgIGxldHRlci1zcGFjaW5nOiAwO1xuICAgICAgbGluZS1oZWlnaHQ6IDE3cHg7XG4gICAgfVxuXG4gICAgJi0tZG93bmxvYWQge1xuICAgICAgcGFkZGluZzogMWVtIDA7XG5cbiAgICAgIGxpIHtcbiAgICAgICAgbGluZS1oZWlnaHQ6IDEuNWVtO1xuICAgICAgfVxuXG4gICAgICBhIHtcbiAgICAgICAgQGluY2x1ZGUgc21vb3RoVGV4dDtcbiAgICAgICAgcG9zaXRpb246IHJlbGF0aXZlO1xuICAgICAgICBwYWRkaW5nLWxlZnQ6IDI2cHg7XG4gICAgICAgIGNvbG9yOiAkYmx1ZTtcbiAgICAgICAgZm9udC13ZWlnaHQ6IGJvbGQ7XG5cbiAgICAgICAgJjpiZWZvcmUge1xuICAgICAgICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICAgICAgICB0b3A6IDA7XG4gICAgICAgICAgbGVmdDogMDtcbiAgICAgICAgICBmb250LWZhbWlseTogZGFzaGljb25zO1xuICAgICAgICAgIGNvbnRlbnQ6IFwiXFxmMzQ2XCI7XG4gICAgICAgICAgZGlzcGxheTogYmxvY2s7XG4gICAgICAgICAgd2lkdGg6IDE2cHg7XG4gICAgICAgICAgaGVpZ2h0OiAxNnB4O1xuICAgICAgICAgIGxpbmUtaGVpZ2h0OiAxNnB4O1xuICAgICAgICAgIGZvbnQtc2l6ZTogMTRweDtcbiAgICAgICAgICBib3JkZXItcmFkaXVzOiA1MCU7XG4gICAgICAgICAgdGV4dC1hbGlnbjogY2VudGVyO1xuICAgICAgICAgIGNvbG9yOiAkd2hpdGU7XG4gICAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogJHByaW1hcnk7XG4gICAgICAgIH1cblxuICAgICAgICAmOmhvdmVyIHtcbiAgICAgICAgICBjb2xvcjogJHByaW1hcnk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAmX19wbHVnaW57XG4gICAgLnNmX19ub3RpY2UtLXN0YXJ0IGF7XG4gICAgICBkaXNwbGF5OiBub25lO1xuICAgIH1cbiAgfVxuXG5cbiAgQGluY2x1ZGUgYnJlYWtwb2ludHMobWQpIHtcbiAgICAmX19jb2x1bW5zIHtcbiAgICAgIGRpc3BsYXk6IGZsZXg7XG4gICAgICBmbGV4LXdyYXA6IHdyYXA7XG4gICAgfVxuICAgICZfX2NvbHVtbiB7XG4gICAgICBmbGV4LWJhc2lzOiA2NiU7XG5cbiAgICAgICY6bGFzdC1jaGlsZCB7XG4gICAgICAgIGZsZXgtYmFzaXM6IDMzJTtcbiAgICAgIH1cbiAgICB9XG5cbiAgfVxufVxuIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBR0FBLEFBQUEsY0FBYyxDQUFDO0VBQ1gsTUFBTSxFQUFFLGNBQWM7RUFDdEIsYUFBYSxFQUFFLEdBQUc7RUFDbEIsS0FBSyxFQUFFLElBQUksR0FDZDs7QUFF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 */ -
shopping-feed/tags/6.1.0/assets/scss/main/_sf.scss
r2339808 r2670662 1 1 .sf { 2 3 &__inline{ 4 display: inline-block; 5 margin-right: 0; 6 } 7 8 &__table { 9 tr:first-child button{ 10 display: none; 11 } 12 td { 13 padding-left: 0; 14 } 15 } 2 16 3 17 &__logo { … … 29 43 } 30 44 45 &__button__secondary.button, 31 46 &__button__logout.button { 32 47 color: $white; -
shopping-feed/tags/6.1.0/readme.txt
r2613147 r2670662 2 2 Contributors: ShoppingFeed, BeAPI 3 3 Tags: shoppingfeed, marketplace, woocommerce, woocommerce shoppingfeed, create woocommerce products shoppingfeed, products feed, generate shoppingfeed, amazon, Jet, Walmart, many marketplace, import orders 4 Stable tag: 6. 0.335 Version: 6. 0.334 Stable tag: 6.1.0 5 Version: 6.1.0 6 6 Requires PHP: 5.6 7 7 Requires at least: 5.2 … … 46 46 6.0.31 Do not send mails to other customers 47 47 6.0.32 Add link to WC logs 48 6. 0.33 Fix priority issue with other plugins48 6.1.0 Add the possibility to connect multiple ShoppingFeed accounts to one WC shop 49 49 50 50 == Description == -
shopping-feed/tags/6.1.0/shoppingfeed.php
r2613147 r2670662 8 8 * Text Domain: shopping-feed 9 9 * Domain Path: /languages 10 * Version: 6. 0.3310 * Version: 6.1.0 11 11 * Requires at least WP: 5.7 12 12 * Requires at least WooCommerce: 5.1.0 … … 26 26 } 27 27 28 define( 'SF_VERSION', '6.0.33' ); 28 define( 'SF_VERSION', '6.1.0' ); 29 define( 'SF_DB_VERSION_SLUG', 'SF_DB_VERSION' ); 30 define( 'SF_DB_VERSION', '1.0.0' ); 31 define( 'SF_UPGRADE_RUNNING', 'SF_UPGRADE_RUNNING' ); 29 32 define( 'SF_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); 30 33 define( 'SF_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); … … 53 56 } 54 57 55 \add_action( 'plugins_loaded', __NAMESPACE__ . '\\init', 100);58 \add_action( 'plugins_loaded', __NAMESPACE__ . '\\init', 99 ); -
shopping-feed/tags/6.1.0/src/Actions/Actions.php
r2339808 r2670662 37 37 */ 38 38 public static function register_get_orders() { 39 as_schedule_recurring_action( 40 time() + 60, 41 ShoppingFeedHelper::get_sf_orders_import_frequency(), 42 'sf_get_orders_action', 43 array(), 44 self::ORDERS_GROUP 45 ); 39 $sf_accounts = ShoppingFeedHelper::get_sf_account_options(); 40 if ( empty( $sf_accounts ) ) { 41 ShoppingFeedHelper::get_logger()->error( 42 sprintf( 43 __( 'No Accounts founds', 'shopping-feed' ) 44 ), 45 array( 46 'source' => 'shopping-feed', 47 ) 48 ); 49 50 return; 51 } 52 foreach ( $sf_accounts as $key => $sf_account ) { 53 as_schedule_recurring_action( 54 time() + 60, 55 ShoppingFeedHelper::get_sf_orders_import_frequency(), 56 'sf_get_orders_action_' . $key, 57 array( 58 'sf_account' => $sf_account, 59 ), 60 self::ORDERS_GROUP 61 ); 62 } 46 63 } 47 64 -
shopping-feed/tags/6.1.0/src/Admin/Metabox.php
r2339808 r2670662 64 64 } 65 65 66 $reference = $order->get_meta( Query:: $wc_meta_sf_reference);67 $channel_name = $order->get_meta( Query:: $wc_meta_sf_channel_name);66 $reference = $order->get_meta( Query::WC_META_SF_REFERENCE ); 67 $channel_name = $order->get_meta( Query::WC_META_SF_CHANNEL_NAME ); 68 68 69 69 if ( empty( $reference ) && empty( $channel_name ) ) : ?> -
shopping-feed/tags/6.1.0/src/Admin/Notices.php
r2339808 r2670662 20 20 21 21 public function admin_notices() { 22 $options = ShoppingFeedHelper::get_sf_account_options(); 23 if ( 24 empty( $options['token'] ) && 25 get_current_screen()->parent_base !== Options::SF_SLUG ) { 26 if ( empty( $options['username'] ) || empty( $options['password'] ) ) { 27 $this->display_notice(); 28 } 29 } 22 //TODO: CHECK ALL CREDENTIALS 23 return; 24 // $options = ShoppingFeedHelper::get_sf_account_options(); 25 // if ( 26 // empty( $options['token'] ) && 27 // get_current_screen()->parent_base !== Options::SF_SLUG ) { 28 // if ( empty( $options['username'] ) || empty( $options['password'] ) ) { 29 // $this->display_notice(); 30 // } 31 // } 30 32 } 31 33 -
shopping-feed/tags/6.1.0/src/Admin/Options.php
r2602861 r2670662 58 58 /** @var array $sf_orders_options */ 59 59 private $sf_orders_options; 60 /** @var bool $connected */ 61 private $connected = true; 60 62 61 63 62 /** … … 114 113 ); 115 114 115 /** 116 * Clean and register new cron once account option updated 117 */ 116 118 add_action( 117 'admin_action_ sf_logout',118 function () { 119 delete_option( Options::SF_ACCOUNT_OPTIONS);120 wp_safe_redirect( ShoppingFeedHelper::get_setting_link(), 302);119 'admin_action_update', 120 function () { 121 Actions::clean_get_orders(); 122 Actions::register_get_orders(); 121 123 } 122 124 ); … … 225 227 */ 226 228 public function init_account_setting_page() { 227 $this->connected = ShoppingFeedHelper::is_authenticated();228 229 229 //check clean action 230 230 $this->check_clean_action(); … … 240 240 self::SF_ACCOUNT_SETTINGS_PAGE 241 241 ); 242 243 add_settings_field(244 'username',245 __( 'Username', 'shopping-feed' ),246 function () {247 printf(248 '<input class="regular-text" type="text" name="sf_account_options[username]" id="username" value="%s">',249 isset( $this->sf_account_options['username'] ) ? esc_attr( $this->sf_account_options['username'] ) : ''250 );251 },252 self::SF_ACCOUNT_SETTINGS_PAGE,253 'sf_account_settings'254 );255 256 add_settings_field(257 'password',258 __( 'Password', 'shopping-feed' ),259 function () {260 printf(261 '<input class="regular-text" type="password" name="sf_account_options[password]" id="password" value="%s">',262 isset( $this->sf_account_options['password'] ) ? esc_attr( $this->sf_account_options['password'] ) : ''263 );264 },265 self::SF_ACCOUNT_SETTINGS_PAGE,266 'sf_account_settings'267 );268 269 if ( $this->connected ) {270 add_settings_field(271 'url',272 __( 'Your source feed', 'shopping-feed' ),273 function () {274 $sf_feed_public_url = ShoppingFeedHelper::get_public_feed_url();275 $sf_process_running = ShoppingFeedHelper::generation_process_running();276 $sf_last_generation_date = get_option( Generator::SF_FEED_LAST_GENERATION_DATE );277 ?>278 <?php if ( ! $sf_process_running ) : ?>279 <a href="<?php echo esc_html( $sf_feed_public_url ); ?>" target="_blank">280 <?php281 echo esc_url( $sf_feed_public_url );282 ;283 ?>284 </a>285 <?php endif; ?>286 <br>287 <p>288 <?php if ( ! $sf_process_running ) : ?>289 <?php esc_html_e( 'Last update', 'shopping-feed' ); ?> :290 <?php291 ! empty( $sf_last_generation_date ) ? esc_html( $sf_last_generation_date ) : esc_html_e( 'Never', 'shopping-feed' );292 ?>293 <a href="<?php echo esc_url( ShoppingFeedHelper::get_public_feed_url_with_generation() ); ?>" target="_blank">294 <?php esc_html_e( 'Refresh', 'shopping-feed' ); ?>295 </a>296 <?php else : ?>297 <strong>(<?php esc_html_e( 'The feed is update is running', 'shopping-feed' ); ?>) <a href="#" onClick="window.location.reload();"><?php esc_html_e( 'Refresh to check progress', 'shopping-feed' ); ?></a></strong>298 <?php endif; ?>299 </p>300 <?php301 },302 self::SF_ACCOUNT_SETTINGS_PAGE,303 'sf_account_settings'304 );305 }306 307 add_settings_field(308 'status',309 __( 'Status', 'shopping-feed' ),310 function () {311 ?>312 <div class="notice-<?php echo esc_html( $this->connected ? 'success' : 'error' ); ?> regular-text notice-alt">313 <?php314 echo esc_html( $this->connected ? _e( 'Connected', 'shopping-feed' ) : _e( 'Not connected', 'shopping-feed' ) );315 ?>316 </div>317 <?php318 },319 self::SF_ACCOUNT_SETTINGS_PAGE,320 'sf_account_settings'321 );322 242 ?> 323 243 <div class="wrap"> 324 244 <?php settings_errors(); ?> 325 245 326 <div class="sf__columns"> 327 <div class="sf__column"> 328 <form method="post" action="options.php"> 329 <?php 330 settings_fields( 'sf_account_page_fields' ); 331 do_settings_sections( self::SF_ACCOUNT_SETTINGS_PAGE ); 332 if ( ! $this->connected ) { 333 submit_button( __( 'Login', 'shopping-feed' ), 'sf__button' ); 334 } else { 335 echo '<input class="hidden" name="action" value="sf_logout">'; 336 submit_button( __( 'Logout', 'shopping-feed' ), 'sf__button__logout', 'logout' ); 337 } 338 ?> 339 </form> 340 <div class="sf__requirements"> 341 <?php 342 $requirements = Requirements::get_instance(); 343 echo wp_kses_post( $requirements->curl_requirement() ); 344 echo wp_kses_post( $requirements->php_requirement() ); 345 echo wp_kses_post( $requirements->openssl_requirement() ); 346 echo wp_kses_post( $requirements->account_requirement() ); 347 echo wp_kses_post( $requirements->uploads_directory_access_requirement() ); 348 ?> 246 <div class="sf__columns"> 247 <div class="sf__column account__wrapper"> 248 <form method="post" action="options.php"> 249 <div class="blocks"> 250 <div class="block_links"> 251 <table class="form-table sf__table"> 252 <thead> 253 <tr> 254 <th> <?php esc_html_e( 'Username', 'shopping-feed' ); ?> </th> 255 <th> <?php esc_html_e( 'Password', 'shopping-feed' ); ?> </th> 256 <th></th> 257 </tr> 258 </thead> 259 <tbody> 260 <tr> 261 <td><input class="regular-text user" type="text" 262 name="sf_account_options[0][username]" 263 value="<?php echo isset( $this->sf_account_options[0]['username'] ) ? esc_attr( $this->sf_account_options[0]['username'] ) : ''; ?>"> 264 </td> 265 <td><input class="regular-text pass" type="password" 266 name="sf_account_options[0][password]" 267 value="<?php echo isset( $this->sf_account_options[0]['password'] ) ? esc_attr( $this->sf_account_options[0]['password'] ) : ''; ?>"> 268 </td> 269 <td> 270 <button class="button sf__button__secondary delete_link sf__button--delete"> 271 Delete 272 </button> 273 </td> 274 <td class="hidden"><input name="sf_account_options[0][token]" 275 value="<?php echo isset( $this->sf_account_options[0]['token'] ) ? esc_attr( $this->sf_account_options[0]['token'] ) : ''; ?>"> 276 </td> 277 <td class="hidden"><input name="sf_account_options[0][sf_store_id]" 278 value="<?php echo isset( $this->sf_account_options[0]['sf_store_id'] ) ? esc_attr( $this->sf_account_options[0]['sf_store_id'] ) : ''; ?>"> 279 </td> 280 </tr> 281 <?php 282 if ( count( $this->sf_account_options ) > 1 ) { 283 foreach ( $this->sf_account_options as $key => $sf_account_option ) { 284 if ( 0 === $key ) { 285 continue; 286 } 287 ?> 288 <tr> 289 <td><input class="regular-text user" type="text" 290 name="sf_account_options[<?php echo esc_attr( $key ); ?>][username]" 291 value="<?php echo isset( $this->sf_account_options[ $key ]['username'] ) ? esc_attr( $this->sf_account_options[ $key ]['username'] ) : ''; ?>"> 292 </td> 293 <td><input class="regular-text pass" type="password" 294 name="sf_account_options[<?php echo esc_attr( $key ); ?>][password]" 295 value="<?php echo isset( $this->sf_account_options[ $key ]['password'] ) ? esc_attr( $this->sf_account_options[ $key ]['password'] ) : ''; ?>"> 296 </td> 297 <td class="hidden"><input 298 name="sf_account_options[<?php echo esc_attr( $key ); ?>][token]" 299 value="<?php echo isset( $this->sf_account_options[ $key ]['token'] ) ? esc_attr( $this->sf_account_options[ $key ]['token'] ) : ''; ?>"> 300 </td> 301 <td class="hidden"><input 302 name="sf_account_options[<?php echo esc_attr( $key ); ?>][sf_store_id]" 303 value="<?php echo isset( $this->sf_account_options[ $key ]['sf_store_id'] ) ? esc_attr( $this->sf_account_options[ $key ]['sf_store_id'] ) : ''; ?>"> 304 </td> 305 <td> 306 <button class="button sf__button__secondary delete_link sf__button--delete"> 307 Delete 308 </button> 309 </td> 310 </tr> 311 <?php 312 } 313 } 314 ?> 315 </tbody> 316 </table> 317 <div class="sf__inline"> 318 <p> 319 <button class="button sf__button__secondary add_link"><?php esc_html_e( 'Add account', 'shopping-feed' ); ?></button> 320 </p> 321 </div> 322 <div class="sf__inline"> 323 <?php 324 settings_fields( 'sf_account_page_fields' ); 325 submit_button( __( 'Save', 'shopping-feed' ), 'sf__button' ); 326 ?> 327 </div> 328 </form> 329 </div> 330 </div> 331 <!-- Line template --> 332 <script type="text/html" id="tpl-line"> 333 <tr> 334 <td><input class="regular-text user" type="text" name="sf_account_options[<%= row %>][username]" 335 value="<%= user %>"></td> 336 <td><input class="regular-text pass" type="password" name="sf_account_options[<%= row %>][password]" 337 value="<%= pass %>"></td> 338 <td> 339 <button class="button sf__button__secondary sf__button--delete delete_link">Delete</button> 340 </td> 341 </tr> 342 </script> 343 <div class="sf__requirements"> 344 <?php 345 $requirements = Requirements::get_instance(); 346 echo wp_kses_post( $requirements->curl_requirement() ); 347 echo wp_kses_post( $requirements->php_requirement() ); 348 echo wp_kses_post( $requirements->openssl_requirement() ); 349 echo wp_kses_post( $requirements->uploads_directory_access_requirement() ); 350 ?> 349 351 <!-- REQUIREMENTS --> 350 352 </div> … … 365 367 private function check_clean_action() { 366 368 if ( ! empty( $_GET['clean_process'] ) ) { 367 ShoppingFeedHelper::clean_ generation_process_running();369 ShoppingFeedHelper::clean_process_running( 'sf_feed_generation_process' ); 368 370 } 369 371 } … … 385 387 ); 386 388 389 wp_enqueue_script( 390 'accounts', 391 SF_PLUGIN_URL . 'assets/js/accounts.js', 392 array( 'jquery', 'underscore' ), 393 true, 394 true 395 ); 396 387 397 wp_enqueue_script( 'multi_js_init', SF_PLUGIN_URL . 'assets/js/init.js', array( 'multi_js' ), true ); 388 398 wp_localize_script( … … 390 400 'sf_options', 391 401 array( 392 'selected_orders' => __( 'Selected order status', 'shopping-feed' ),402 'selected_orders' => __( 'Selected order status', 'shopping-feed' ), 393 403 'unselected_orders' => __( 'Unselected order status', 'shopping-feed' ), 394 'search' => __( 'Search', 'shopping-feed' ),404 'search' => __( 'Search', 'shopping-feed' ), 395 405 ) 396 406 ); … … 401 411 */ 402 412 private function init_feed_setting_page() { 403 $this->check_connection();404 413 405 414 //load assets … … 413 422 }, 414 423 self::SF_FEED_SETTINGS_PAGE 424 ); 425 426 add_settings_field( 427 'url', 428 __( 'Your source feed', 'shopping-feed' ), 429 function () { 430 $sf_feed_public_url = ShoppingFeedHelper::get_public_feed_url(); 431 $sf_process_running = ShoppingFeedHelper::is_process_running( 'sf_feed_generation_process' ); 432 $sf_last_generation_date = get_option( Generator::SF_FEED_LAST_GENERATION_DATE ); 433 ?> 434 <?php if ( ! $sf_process_running ) : ?> 435 <a href="<?php echo esc_html( $sf_feed_public_url ); ?>" target="_blank"> 436 <?php 437 echo esc_url( $sf_feed_public_url ); 438 ; 439 ?> 440 </a> 441 <?php endif; ?> 442 <br> 443 <p> 444 <?php if ( ! $sf_process_running ) : ?> 445 <?php esc_html_e( 'Last update', 'shopping-feed' ); ?> : 446 <?php 447 echo ! empty( $sf_last_generation_date ) ? esc_html( $sf_last_generation_date ) : esc_html__( 'Never', 'shopping-feed' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 448 ?> 449 <a href="<?php echo esc_url( ShoppingFeedHelper::get_public_feed_url_with_generation() ); ?>" target="_blank"> 450 <?php esc_html_e( 'Refresh', 'shopping-feed' ); ?> 451 </a> 452 <?php else : ?> 453 <strong>(<?php esc_html_e( 'The feed is update is running', 'shopping-feed' ); ?>) <a href="#" onClick="window.location.reload();"><?php esc_html_e( 'Refresh to check progress', 'shopping-feed' ); ?></a></strong> 454 <?php endif; ?> 455 </p> 456 <?php 457 }, 458 self::SF_FEED_SETTINGS_PAGE, 459 'sf_feed_settings_categories' 415 460 ); 416 461 … … 554 599 __( 'Batch size', 'shopping-feed' ), 555 600 function () { 556 $running_process = ShoppingFeedHelper::get_running_ generation_feed_process();601 $running_process = ShoppingFeedHelper::get_running_process( 'sf_feed_generation_process' ); 557 602 $running_process = is_array( $running_process ) ? count( $running_process ) : 0; 558 603 ?> … … 657 702 658 703 /** 659 * Check connection with SF platform with correct credentials660 * If not redirect to Account page661 */662 private function check_connection() {663 if ( ! ShoppingFeedHelper::is_authenticated() ) {664 wp_safe_redirect( sprintf( '%s&no_connected=%s', ShoppingFeedHelper::get_setting_link(), 'true' ) );665 }666 }667 668 /**669 704 * Define Shipping Page 670 705 */ 671 706 private function init_shipping_setting_page() { 672 $this->check_connection();673 674 707 //load assets 675 708 $this->load_assets(); … … 826 859 827 860 private function init_orders_setting_page() { 828 $this->check_connection();829 830 861 //load assets 831 862 $this->load_assets(); -
shopping-feed/tags/6.1.0/src/Admin/Requirements.php
r2542211 r2670662 83 83 * @return string 84 84 */ 85 public function account_requirement() {86 return ( $this->valid_account() )87 ? '<p class="success">' . __( 'You are logged in your ShoppingFeed account.', 'shopping-feed' ) . '</p>'88 : '<p class="failed">' . __( 'You must be logged in your ShoppingFeed account.', 'shopping-feed' ) . '</p>';89 }90 91 92 /**93 * @return string94 */95 85 public function uploads_directory_access_requirement() { 96 86 return ( $this->uploads_directory_writable() ) … … 137 127 138 128 /** 139 * Check if the user is logged in.140 *141 * @return bool142 */143 public function valid_account() {144 return ShoppingFeedHelper::is_authenticated();145 }146 147 /**148 129 * Check if the uploads directory is writable 149 130 * -
shopping-feed/tags/6.1.0/src/Admin/WoocommerceActions.php
r2542211 r2670662 10 10 use ShoppingFeed\Sdk\Api\Catalog\PricingUpdate; 11 11 use ShoppingFeed\Sdk\Api\Store\StoreResource; 12 use ShoppingFeed\Sdk\Client; 13 use ShoppingFeed\Sdk\Credential; 12 14 use ShoppingFeed\ShoppingFeedWC\Feed\AsyncGenerator; 13 15 use ShoppingFeed\ShoppingFeedWC\Feed\Generator; … … 16 18 use ShoppingFeed\ShoppingFeedWC\Orders\Orders; 17 19 use ShoppingFeed\ShoppingFeedWC\Products\Product; 20 use ShoppingFeed\ShoppingFeedWC\Query\Query; 18 21 use ShoppingFeed\ShoppingFeedWC\Sdk\Sdk; 19 22 use ShoppingFeed\ShoppingFeedWC\ShoppingFeedHelper; 20 21 23 22 24 /** … … 63 65 add_action( 64 66 'sf_feed_generation_combine_feed_parts', 65 [67 array( 66 68 AsyncGenerator::get_instance(), 67 69 'combine_feed_parts', 68 ]70 ) 69 71 ); 70 72 … … 84 86 85 87 //Get Orders 86 add_action( 87 'sf_get_orders_action', 88 function () { 89 Orders::get_instance()->get_orders(); 90 } 91 ); 88 $sf_accounts = ShoppingFeedHelper::get_sf_account_options(); 89 if ( empty( $sf_accounts ) ) { 90 ShoppingFeedHelper::get_logger()->error( 91 sprintf( 92 __( 'No Accounts founds', 'shopping-feed' ) 93 ), 94 array( 95 'source' => 'shopping-feed', 96 ) 97 ); 98 } else { 99 foreach ( $sf_accounts as $key => $sf_account ) { 100 add_action( 101 'sf_get_orders_action_' . $key, 102 function ( $sf_account ) { 103 Orders::get_instance()->get_orders( $sf_account ); 104 } 105 ); 106 } 107 } 92 108 93 109 //Acknowledge Remain Order … … 102 118 103 119 /** 120 * Migrate old accounts to multi account format 121 */ 122 add_action( 'sf_migrate_single_action', array( $this, 'migrate_old_accounts' ) ); 123 124 /** 104 125 * Orders Statuses Mapping 105 126 * Each status with action … … 107 128 */ 108 129 $statuses_actions = ShoppingFeedHelper::get_sf_statuses_actions(); 109 if ( 0 < $statuses_actions ) { 110 foreach ( $statuses_actions as $sf_action => $wc_statuses ) { 111 if ( ! is_array( $wc_statuses ) || '' === $sf_action ) { 112 continue; 113 } 114 115 foreach ( $wc_statuses as $wc_status ) { 116 $status = str_replace( 'wc-', '', $wc_status ); 117 $action = 'woocommerce_order_status_' . $status; 118 add_action( 119 $action, 120 function ( $order_id ) use ( $sf_action ) { 121 //if its not a sf order 122 if ( ! Order::is_sf_order( $order_id ) ) { 123 return; 124 } 125 try { 126 $operations = new Operations( $order_id ); 127 if ( ! method_exists( $operations, $sf_action ) ) { 128 ShoppingFeedHelper::get_logger()->error( 129 sprintf( 130 /* translators: %s: Action name. */ 131 __( 'Cant find any matched method for %s', 'shopping-feed' ), 132 $sf_action 133 ), 134 array( 135 'source' => 'shopping-feed', 136 ) 137 ); 138 139 return; 140 } 141 call_user_func( array( $operations, $sf_action ) ); 142 } catch ( Exception $exception ) { 143 wc_get_order( $order_id )->add_order_note( 144 sprintf( 145 /* translators: %s: Action */ 146 __( 'Failed to %s order', 'shopping-feed' ), 147 ucfirst( $sf_action ) 148 ) 149 ); 130 if ( empty( $statuses_actions ) ) { 131 return; 132 } 133 foreach ( $statuses_actions as $sf_action => $wc_statuses ) { 134 if ( ! is_array( $wc_statuses ) || '' === $sf_action ) { 135 continue; 136 } 137 138 foreach ( $wc_statuses as $wc_status ) { 139 $status = str_replace( 'wc-', '', $wc_status ); 140 $action = 'woocommerce_order_status_' . $status; 141 add_action( 142 $action, 143 function ( $order_id ) use ( $sf_action ) { 144 //if its not a sf order 145 if ( ! Order::is_sf_order( $order_id ) ) { 146 return; 147 } 148 try { 149 $operations = new Operations( $order_id ); 150 if ( ! method_exists( $operations, $sf_action ) ) { 150 151 ShoppingFeedHelper::get_logger()->error( 151 152 sprintf( 152 /* translators: %1$s: Action. %2$s: Error Message */ 153 __( 'Failed to %1$s order => %2$s', 'shopping-feed' ), 154 ucfirst( $sf_action ), 155 $exception->getMessage() 153 /* translators: %s: Action name. */ 154 __( 'Cant find any matched method for %s', 'shopping-feed' ), 155 $sf_action 156 156 ), 157 157 array( … … 159 159 ) 160 160 ); 161 162 return; 161 163 } 164 call_user_func( array( $operations, $sf_action ) ); 165 } catch ( Exception $exception ) { 166 wc_get_order( $order_id )->add_order_note( 167 sprintf( 168 /* translators: %s: Action */ 169 __( 'Failed to %s order', 'shopping-feed' ), 170 ucfirst( $sf_action ) 171 ) 172 ); 173 ShoppingFeedHelper::get_logger()->error( 174 sprintf( 175 /* translators: %1$s: Action. %2$s: Error Message */ 176 __( 'Failed to %1$s order => %2$s', 'shopping-feed' ), 177 ucfirst( $sf_action ), 178 $exception->getMessage() 179 ), 180 array( 181 'source' => 'shopping-feed', 182 ) 183 ); 162 184 } 163 );164 }185 } 186 ); 165 187 } 166 188 } … … 182 204 * @param $product_id 183 205 * @param bool $only_stock 184 *185 * @return bool186 206 */ 187 207 public function update_product( $product_id, $only_stock = false ) { 188 $sdk = Sdk::get_instance(); 189 if ( ! $sdk->get_default_shop() instanceof StoreResource ) { 190 ShoppingFeedHelper::get_logger()->error( __( 'Can\'t find default shop', 'shopping-feed' ) ); 191 192 return false; 193 } 194 195 /** @var StoreResource $shop */ 196 $shop = $sdk->get_default_shop(); 197 $pricing_api = $shop->getPricingApi(); 198 $inventory_api = $shop->getInventoryApi(); 199 200 $this->pricing_update = new \ShoppingFeed\Sdk\Api\Catalog\PricingUpdate(); 201 $this->inventory_update = new \ShoppingFeed\Sdk\Api\Catalog\InventoryUpdate(); 202 203 $product = new Product( $product_id ); 204 if ( $product->has_variations() ) { 205 foreach ( $product->get_variations() as $variation ) { 206 if ( empty( $variation['sku'] ) ) { 207 ShoppingFeedHelper::get_logger()->warning( 208 sprintf( 209 /* translators: %s: Product ID. */ 210 __( 'Cant update product without SKU => %s', 'shopping-feed' ), 211 $product_id 212 ), 213 array( 214 'source' => 'shopping-feed', 215 ) 216 ); 217 218 continue; 219 } 220 221 $this->may_update_pricing( $variation['sku'], ! empty( $variation['discount'] ) ? $variation['discount'] : $variation['price'] ); 222 $this->may_update_inventory( $variation['sku'], $variation['quantity'] ); 223 } 224 } else { 225 if ( empty( $product->get_sku() ) ) { 226 ShoppingFeedHelper::get_logger()->warning( 208 $sf_accounts = ShoppingFeedHelper::get_sf_account_options(); 209 if ( empty( $sf_accounts ) ) { 210 ShoppingFeedHelper::get_logger()->error( 211 sprintf( 212 __( 'No Accounts founds', 'shopping-feed' ) 213 ), 214 array( 215 'source' => 'shopping-feed', 216 ) 217 ); 218 219 return; 220 } 221 222 foreach ( $sf_accounts as $sf_account ) { 223 $shop = Sdk::get_sf_shop( $sf_account ); 224 if ( ! $shop instanceof StoreResource ) { 225 ShoppingFeedHelper::get_logger()->error( 227 226 sprintf( 228 /* translators: %s: Product ID. */229 __( 'Can t update product without SKU =>%s', 'shopping-feed' ),230 $ product_id227 /* translators: %s: Error message. */ 228 __( 'Cannot retrieve shop from SDK for account : %s', 'shopping-feed' ), 229 $sf_account['username'] 231 230 ), 232 231 array( … … 234 233 ) 235 234 ); 235 continue; 236 } 237 238 $pricing_api = $shop->getPricingApi(); 239 $inventory_api = $shop->getInventoryApi(); 240 241 $this->pricing_update = new \ShoppingFeed\Sdk\Api\Catalog\PricingUpdate(); 242 $this->inventory_update = new \ShoppingFeed\Sdk\Api\Catalog\InventoryUpdate(); 243 244 $product = new Product( $product_id ); 245 if ( $product->has_variations() ) { 246 if ( ! $this->update_variation_product( $product ) ) { 247 continue; 248 } 249 } else { 250 if ( ! $this->update_normal_product( $product ) ) { 251 continue; 252 } 253 } 254 /** 255 * Check if we need to update the price or only the stock 256 */ 257 if ( ! $only_stock ) { 258 /** 259 * Send api request to update the price 260 */ 261 $pricing_api->execute( $this->pricing_update ); 262 } 263 264 /** 265 * Send api request to update the inventory 266 */ 267 $inventory_api->execute( $this->inventory_update ); 268 } 269 } 270 271 /** 272 * @param Product $product 273 * 274 * @psalm-suppress all 275 */ 276 public function update_normal_product( $product ) { 277 if ( empty( $product->get_sku() ) ) { 278 ShoppingFeedHelper::get_logger()->warning( 279 sprintf( 280 /* translators: %s: Product ID. */ 281 __( 'Cant update product without SKU => %s', 'shopping-feed' ), 282 $product->get_wc_product()->get_id() 283 ), 284 array( 285 'source' => 'shopping-feed', 286 ) 287 ); 288 289 return false; 290 } 291 292 $this->may_update_pricing( $product->get_sku(), ! empty( $product->get_discount() ) ? $product->get_discount() : $product->get_price() ); 293 $this->may_update_inventory( $product->get_sku(), $product->get_quantity() ); 294 295 return true; 296 } 297 298 /** 299 * @param Product $product 300 * 301 * @psalm-suppress all 302 * @return bool 303 */ 304 public function update_variation_product( $product ) { 305 foreach ( $product->get_variations() as $variation ) { 306 if ( empty( $variation['sku'] ) ) { 307 ShoppingFeedHelper::get_logger()->warning( 308 sprintf( 309 /* translators: %s: Product ID. */ 310 __( 'Cant update product without SKU => %s', 'shopping-feed' ), 311 $product->get_wc_product()->get_id() 312 ), 313 array( 314 'source' => 'shopping-feed', 315 ) 316 ); 236 317 237 318 return false; 238 319 } 239 320 240 $this->may_update_pricing( $product->get_sku(), ! empty( $product->get_discount() ) ? $product->get_discount() : $product->get_price() ); 241 $this->may_update_inventory( $product->get_sku(), $product->get_quantity() ); 242 } 243 /** 244 * Check if we need to update the price or only the stock 245 */ 246 if ( ! $only_stock ) { 247 /** 248 * Send api request to update the price 249 */ 250 $pricing_api->execute( $this->pricing_update ); 251 } 252 253 /** 254 * Send api request to update the inventory 255 */ 256 $inventory_api->execute( $this->inventory_update ); 321 $this->may_update_pricing( $variation['sku'], ! empty( $variation['discount'] ) ? $variation['discount'] : $variation['price'] ); 322 $this->may_update_inventory( $variation['sku'], $variation['quantity'] ); 323 } 257 324 258 325 return true; … … 306 373 $this->inventory_update->add( $sku, intval( $inventory ) ); 307 374 } 375 376 /** 377 * @return bool 378 * @throws Exception 379 * @psalm-suppress all 380 */ 381 public function migrate_old_accounts() { 382 //migrate account data and retrieve account ID 383 $account_options = ShoppingFeedHelper::get_sf_account_options(); 384 385 if ( empty( $account_options['token'] ) ) { 386 ShoppingFeedHelper::get_logger()->error( 387 sprintf( 388 __( 'No token founds', 'shopping-feed' ) 389 ), 390 array( 391 'source' => 'shopping-feed', 392 ) 393 ); 394 ShoppingFeedHelper::end_upgrade(); 395 396 return false; 397 } 398 try { 399 $main_store = Client\Client::createSession( new Credential\Token( $account_options['token'] ) )->getMainStore(); 400 if ( is_null( $main_store ) ) { 401 ShoppingFeedHelper::get_logger()->error( 402 sprintf( 403 __( 'Cant retrieve main store', 'shopping-feed' ) 404 ), 405 array( 406 'source' => 'shopping-feed', 407 ) 408 ); 409 410 ShoppingFeedHelper::end_upgrade(); 411 412 return false; 413 } 414 $account_id = $main_store->getId(); 415 $new_account_options = array(); 416 $new_account_options[] = array( 417 'sf_store_id' => $account_id, 418 'username' => ! empty( $account_options['username'] ) ? $account_options['username'] : '', 419 'password' => ! empty( $account_options['password'] ) ? $account_options['password'] : '', 420 'token' => $account_options['token'], 421 ); 422 ShoppingFeedHelper::set_sf_account_options( $new_account_options ); 423 } catch ( \Exception $exception ) { 424 ShoppingFeedHelper::get_logger()->error( 425 sprintf( 426 /* translators: %s: Error message. */ 427 __( 'Cant login with actual credentials => %s', 'shopping-feed' ), 428 $exception->getMessage() 429 ), 430 array( 431 'source' => 'shopping-feed', 432 ) 433 ); 434 435 ShoppingFeedHelper::end_upgrade(); 436 437 return false; 438 } 439 440 //Migrate old orders to default account 441 $args = array( 442 'limit' => - 1, 443 'meta_key' => Query::WC_META_SF_REFERENCE, 444 'meta_compare' => 'EXISTS', 445 ); 446 447 $query = new \WC_Order_Query( $args ); 448 $wc_orders = $query->get_orders(); 449 if ( empty( $wc_orders ) ) { 450 ShoppingFeedHelper::get_logger()->error( 451 sprintf( 452 __( 'No SF orders founds for migration', 'shopping-feed' ) 453 ), 454 array( 455 'source' => 'shopping-feed', 456 ) 457 ); 458 ShoppingFeedHelper::end_upgrade(); 459 460 return false; 461 } 462 463 foreach ( $wc_orders as $wc_order ) { 464 //add store id 465 /** @var \WC_Order $wc_order */ 466 $wc_order->add_meta_data( Query::WC_META_SF_STORE_ID, $account_id ); 467 $wc_order->save(); 468 } 469 470 ShoppingFeedHelper::end_upgrade(); 471 472 return true; 473 } 308 474 } -
shopping-feed/tags/6.1.0/src/Feed/Generator.php
r2542211 r2670662 234 234 235 235 if ( true === $no_cache || ! is_file( $file_path ) ) { 236 if ( ShoppingFeedHelper:: generation_process_running() ) {236 if ( ShoppingFeedHelper::is_process_running( 'sf_feed_generation_process' ) ) { 237 237 wp_die( 'Feed generation already launched' ); 238 238 } -
shopping-feed/tags/6.1.0/src/Orders/Operations.php
r2542211 r2670662 53 53 */ 54 54 public function __construct( $order_id ) { 55 $sdk = Sdk::get_instance(); 56 if ( ! $sdk->get_default_shop() instanceof StoreResource ) { 55 //Check if the order from SF and return it with metas data 56 $order_sf_metas = Order::get_order_sf_metas( $order_id ); 57 if ( 58 empty( $order_sf_metas ) || 59 empty( $order_sf_metas['sf_store_id'] ) 60 ) { 61 throw new Exception( 62 sprintf( 63 /* translators: %s: Error message. */ 64 __( 'No SF order found in %s', 'shopping-feed' ), 65 $order_id 66 ) 67 ); 68 } 69 70 $account_id = $order_sf_metas['sf_store_id']; 71 72 $shop = Sdk::get_sf_account_shop( $account_id ); 73 74 if ( ! $shop instanceof StoreResource ) { 75 ShoppingFeedHelper::get_logger()->error( 76 sprintf( 77 /* translators: %s: Error message. */ 78 __( 'Cannot retrieve shop from SDK for account : %s', 'shopping-feed' ), 79 $account_id 80 ), 81 array( 82 'source' => 'shopping-feed', 83 ) 84 ); 57 85 throw new Exception( 58 86 __( 'No store found', 'shopping-feed' ) 59 87 ); 60 88 } 61 /** @var StoreResource $default_shop */62 $default_shop = $sdk->get_default_shop();63 64 //Check if the order from SF and return it with metas data65 $order_sf_metas = Order::get_order_sf_metas( $order_id );66 if ( empty( $order_sf_metas ) ) {67 throw new Exception(68 __( 'No Order found', 'shopping-feed' )69 );70 }71 89 72 90 $this->wc_order = $order_sf_metas['order']; 73 $this->order_api = $ default_shop->getOrderApi();91 $this->order_api = $shop->getOrderApi(); 74 92 $this->order_operation = new OrderOperation(); 75 93 $this->sf_reference = (string) $order_sf_metas['sf_reference']; -
shopping-feed/tags/6.1.0/src/Orders/Order.php
r2551274 r2670662 221 221 */ 222 222 public static function exists( $sf_order ) { 223 return ! empty( wc_get_orders( array( Query:: $wc_meta_sf_reference=> $sf_order->getReference() ) ) );223 return ! empty( wc_get_orders( array( Query::WC_META_SF_REFERENCE => $sf_order->getReference() ) ) ); 224 224 } 225 225 … … 313 313 } 314 314 315 $sf_reference = $order->get_meta( Query::$wc_meta_sf_reference ); 316 $sf_channel_name = $order->get_meta( Query::$wc_meta_sf_channel_name ); 315 $sf_store_id = $order->get_meta( Query::WC_META_SF_STORE_ID ); 316 $sf_reference = $order->get_meta( Query::WC_META_SF_REFERENCE ); 317 $sf_channel_name = $order->get_meta( Query::WC_META_SF_CHANNEL_NAME ); 317 318 318 319 return array( 319 320 'order' => $order, 321 'sf_store_id' => $sf_store_id, 320 322 'sf_reference' => $sf_reference, 321 323 'sf_channel_name' => $sf_channel_name, … … 336 338 } 337 339 338 return ! empty( $wc_order->get_meta( Query:: $wc_meta_sf_reference) );340 return ! empty( $wc_order->get_meta( Query::WC_META_SF_REFERENCE ) ); 339 341 } 340 342 … … 347 349 */ 348 350 public static function can_update_stock( $wc_order ) { 349 return empty( $wc_order->get_meta( Query:: $wc_meta_sf_reference) ) || empty( $wc_order->get_meta( Metas::$dont_update_inventory ) );351 return empty( $wc_order->get_meta( Query::WC_META_SF_REFERENCE ) ) || empty( $wc_order->get_meta( Metas::$dont_update_inventory ) ); 350 352 } 351 353 } -
shopping-feed/tags/6.1.0/src/Orders/Order/Metas.php
r2339808 r2670662 39 39 $this->add_order_channel_name(); 40 40 $this->add_order_shipping(); 41 $this->add_sf_store_id(); 41 42 42 43 do_action_ref_array( 'sf_add_metas', array( $this ) ); … … 47 48 */ 48 49 private function add_order_referene() { 49 $this->add_meta( Query:: $wc_meta_sf_reference, $this->sf_order->getReference(), true );50 $this->add_meta( Query::WC_META_SF_REFERENCE, $this->sf_order->getReference(), true ); 50 51 } 51 52 … … 54 55 */ 55 56 private function add_order_channel_name() { 56 $this->add_meta( Query:: $wc_meta_sf_channel_name, $this->sf_order->getChannel()->getName() );57 $this->add_meta( Query::WC_META_SF_CHANNEL_NAME, $this->sf_order->getChannel()->getName() ); 57 58 } 58 59 … … 81 82 ); 82 83 } 84 85 /** 86 * Add store id 87 */ 88 private function add_sf_store_id() { 89 $sf_order_array = $this->sf_order->toArray(); 90 $this->add_meta( Query::WC_META_SF_STORE_ID, $sf_order_array['storeId'] ); 91 } 83 92 } -
shopping-feed/tags/6.1.0/src/Orders/Orders.php
r2417980 r2670662 14 14 */ 15 15 class Orders { 16 17 /**18 * @var false|StoreResource19 */20 private $shop;21 16 22 17 /** … … 51 46 52 47 /** 53 * Orders constructor.48 * Get Orders from SF 54 49 */ 55 private function __construct() { 56 if ( empty( $this->shop ) ) { 57 $sdk = Sdk::get_instance(); 58 if ( $sdk->get_default_shop() ) { 59 $this->shop = $sdk->get_default_shop(); 60 } 61 } 62 } 50 public function get_orders( $sf_account ) { 51 $shop = Sdk::get_sf_shop( $sf_account ); 63 52 64 /** 65 * Get Orders from SF 66 * @return bool 67 */ 68 public function get_orders() { 69 if ( ! $this->shop ) { 53 if ( ! $shop instanceof StoreResource ) { 54 ShoppingFeedHelper::get_logger()->error( 55 sprintf( 56 /* translators: %s: Error message. */ 57 __( 'Cannot retrieve shop from SDK for account : %s', 'shopping-feed' ), 58 $sf_account['username'] 59 ), 60 array( 61 'source' => 'shopping-feed', 62 ) 63 ); 70 64 return false; 71 65 } 72 66 73 $order_api = $ this->shop->getOrderApi();67 $order_api = $shop->getOrderApi(); 74 68 $filters = array(); 75 69 $filters['acknowledgment'] = 'unacknowledged'; -
shopping-feed/tags/6.1.0/src/Products/Product.php
r2487968 r2670662 48 48 49 49 return $this; 50 } 51 52 /** 53 * Return WC Product 54 * @return false|\WC_Product|null 55 */ 56 public function get_wc_product() { 57 return $this->product; 50 58 } 51 59 -
shopping-feed/tags/6.1.0/src/Query/Query.php
r2339808 r2670662 10 10 */ 11 11 class Query { 12 /** 13 * Custom Meta for SF accpunt ID 14 */ 15 const WC_META_SF_STORE_ID = 'sf_store_id'; 12 16 13 17 /** 14 18 * Custom Meta for SF reference 15 * @var string16 19 */ 17 public static $wc_meta_sf_reference= 'sf_reference';20 const WC_META_SF_REFERENCE = 'sf_reference'; 18 21 19 22 /** 20 23 * Custom Meta for SF channel name 21 * @var string22 24 */ 23 public static $wc_meta_sf_channel_name= 'sf_marketplace';25 const WC_META_SF_CHANNEL_NAME = 'sf_marketplace'; 24 26 25 27 public function __construct() { … … 44 46 */ 45 47 public function wc_get_by_sf_reference( $query, $query_vars ) { 46 if ( ! empty( $query_vars[ self:: $wc_meta_sf_reference] ) ) {48 if ( ! empty( $query_vars[ self::WC_META_SF_REFERENCE ] ) ) { 47 49 $query['meta_query'][] = array( 48 'key' => self:: $wc_meta_sf_reference,49 'value' => esc_attr( $query_vars[ self:: $wc_meta_sf_reference] ),50 'key' => self::WC_META_SF_REFERENCE, 51 'value' => esc_attr( $query_vars[ self::WC_META_SF_REFERENCE ] ), 50 52 ); 51 53 } -
shopping-feed/tags/6.1.0/src/Sdk/Sdk.php
r2417980 r2670662 6 6 defined( 'ABSPATH' ) || exit; 7 7 8 use ShoppingFeed\Sdk\Api\Session\SessionResource;9 8 use ShoppingFeed\Sdk\Client; 10 9 use ShoppingFeed\Sdk\Credential; … … 16 15 class Sdk { 17 16 18 /** @var SessionResource */ 19 private $session; 17 /** 18 * @param int $account_id 19 */ 20 public static function get_sf_account_shop( $account_id ) { 21 $sf_account = ShoppingFeedHelper::get_sf_account_credentials( $account_id ); 20 22 21 /** @var string|null */22 private $username;23 return self::get_sf_shop( $sf_account ); 24 } 23 25 24 /** @var string|null */25 private $password;26 27 /** @var string|null */28 private $token;29 26 30 27 /** 31 * @var Sdk 28 * Return account deault shop 29 * 30 * @param array $sf_account 31 * 32 * @return false|\ShoppingFeed\Sdk\Api\Store\StoreResource 33 * @psalm-suppress all 32 34 */ 33 private static $instance; 34 35 /** 36 * Get the singleton instance. 37 * 38 * @return Sdk 39 */ 40 public static function get_instance() { 41 if ( is_null( self::$instance ) ) { 42 self::$instance = new static(); 43 } 44 45 return self::$instance; 46 } 47 48 /** 49 * Singleton instance can't be cloned. 50 */ 51 private function __clone() { 52 } 53 54 /** 55 * Singleton instance can't be serialized. 56 */ 57 private function __wakeup() { 58 } 59 60 /** 61 * Sdk constructor. 62 */ 63 private function __construct() { 64 if ( empty( $this->session ) ) { 65 $options = ShoppingFeedHelper::get_sf_account_options(); 66 if ( empty( $options ) ) { 67 ShoppingFeedHelper::get_logger()->error( 68 __( 'No settings founds', 'shopping-feed' ), 69 array( 70 'source' => 'shopping-feed', 71 ) 72 ); 73 74 return; 75 } 76 77 $this->token = ! empty( $options['token'] ) ? $options['token'] : null; 78 $this->username = ! empty( $options['username'] ) ? $options['username'] : null; 79 $this->password = ! empty( $options['password'] ) ? $options['password'] : null; 80 81 $this->authenticate(); 82 } 83 } 84 85 /** 86 * @return Credential\Password|Credential\Token|\WP_Error 87 */ 88 private function get_credential() { 89 90 //Check if we have Token to connect directly 91 if ( ! empty( $this->token ) ) { 92 return new Credential\Token( $this->token ); 93 } 94 95 //If no credentials found go back 96 if ( empty( $this->username ) || empty( $this->password ) ) { 35 public static function get_sf_shop( $sf_account ) { 36 if ( 37 empty( $sf_account['token'] ) && ( 38 empty( $sf_account['username'] ) || 39 empty( $sf_account['password'] ) 40 ) 41 ) { 42 //TODO: add more informations about concerned sf account 97 43 ShoppingFeedHelper::get_logger()->error( 98 __( 'Need username/password to connect', 'shopping-feed' ), 44 sprintf( 45 __( 'No Credentials found to connect', 'shopping-feed' ) 46 ), 99 47 array( 100 48 'source' => 'shopping-feed', 101 49 ) 102 50 ); 103 return new \WP_Error( 'shopping_feed_auth_required', __( 'Need username/password to connect', 'shopping-feed' ) );104 }105 51 106 //Return Credentials username/password107 return new Credential\Password( $this->username, $this->password );108 }109 110 /**111 * Try to connect if we have credentials112 * Set Token if the connection is set113 * @return bool114 */115 public function authenticate() {116 if ( is_wp_error( $this->get_credential() ) ) {117 52 return false; 118 53 } 119 54 120 /** @var Credential\Password|Credential\Token $credentials */ 121 $credentials = $this->get_credential(); 55 $credentials = new Credential\Password( $sf_account['username'], $sf_account['password'] ); 56 57 if ( ! empty( $sf_account['token'] ) ) { 58 $credentials = new Credential\Token( $sf_account['token'] ); 59 } 122 60 123 61 try { 124 $this->session = Client\Client::createSession( $credentials ); 125 126 if ( empty( $this->token ) ) { 127 ShoppingFeedHelper::set_sf_token( $this->session->getToken() ); 128 } 129 130 return true; 62 $session = Client\Client::createSession( $credentials ); 131 63 } catch ( \Exception $exception ) { 132 133 64 ShoppingFeedHelper::get_logger()->error( 134 65 sprintf( … … 142 73 ); 143 74 144 ShoppingFeedHelper::clean_password();145 return false;146 }147 }148 149 /**150 * Return the main store if the connection is set151 * @return false|\ShoppingFeed\Sdk\Api\Store\StoreResource152 */153 public function get_default_shop() {154 155 if ( ! $this->authenticate() ) {156 75 return false; 157 76 } 158 77 159 $main_shop = $ this->session->getMainStore();78 $main_shop = $session->getMainStore(); 160 79 161 if ( ! $main_shop) {80 if ( empty( $main_shop ) ) { 162 81 ShoppingFeedHelper::get_logger()->error( 82 //TODO: add more informations about concerned sf account 163 83 __( 'No store found', 'shopping-feed' ), 164 84 array( … … 166 86 ) 167 87 ); 88 168 89 return false; 169 90 } 91 92 //add storeId to account 93 $account_options = ShoppingFeedHelper::get_sf_account_options(); 94 $index = array_search( $sf_account['username'], array_column( $account_options, 'username' ), true ); 95 if ( false === $index || empty( $account_options[ $index ] ) ) { 96 return false; 97 } 98 $account_options[ $index ]['sf_store_id'] = $main_shop->getId(); 99 $account_options[ $index ]['token'] = $session->getToken(); 100 ShoppingFeedHelper::set_sf_account_options( $account_options ); 170 101 171 102 return $main_shop; -
shopping-feed/tags/6.1.0/src/ShoppingFeed.php
r2542211 r2670662 117 117 } 118 118 119 $this->actions = new WoocommerceActions(); 120 121 //Check Upgrade 122 if ( ! $this->check_upgrade() ) { 123 return; 124 } 125 119 126 $this->query = new Query(); 120 $this->actions = new WoocommerceActions();121 127 $this->filters = new WoocommerceFilters(); 122 128 $this->notices = new Notices(); … … 242 248 delete_option( Options::SF_CARRIERS ); 243 249 delete_option( Generator::SF_FEED_LAST_GENERATION_DATE ); 250 delete_option( SF_DB_VERSION_SLUG ); 251 delete_option( SF_UPGRADE_RUNNING ); 244 252 self::remove_sf_directory(); 245 253 } … … 259 267 } 260 268 } 269 270 public function check_upgrade() { 271 if ( ! ShoppingFeedHelper::sf_has_upgrade() || ShoppingFeedHelper::sf_new_customer() ) { 272 return true; 273 } 274 275 //check if we have a running migration 276 if ( ShoppingFeedHelper::is_upgrade_running() ) { 277 add_action( 278 'admin_notices', 279 function () { 280 ?> 281 <div id="message" class="notice notice-error"> 282 <p><?php esc_html_e( 'ShoppingFeed migration is running', 'shopping-feed' ); ?></p> 283 </div> 284 <?php 285 } 286 ); 287 288 return false; 289 } 290 291 //check if we need to do migration 292 if ( 293 ! empty( $_GET['sf_action'] ) && 294 'sf_migrate_single' === $_GET['sf_action'] && 295 isset( $_GET['_wpnonce'] ) && 296 wp_verify_nonce( wp_unslash( $_GET['_wpnonce'] ), 'sf_migrate_single' ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized 297 ) { 298 $id_action = as_enqueue_async_action( 'sf_migrate_single_action', array(), 'sf_migrate_single' ); 299 update_option( SF_UPGRADE_RUNNING, $id_action ); 300 wp_safe_redirect( admin_url( '/' ), 302 ); 301 exit; 302 } 303 304 add_action( 305 'admin_notices', 306 function () { 307 ?> 308 <div id="message" class="notice notice-error"> 309 <p><?php esc_html_e( 'ShoppingFeed need to migrate old data', 'shopping-feed' ); ?></p> 310 <a href=" 311 <?php 312 echo esc_url( 313 wp_nonce_url( 314 add_query_arg( 315 array( 316 'sf_action' => 'sf_migrate_single', 317 ), 318 admin_url() 319 ), 320 'sf_migrate_single' 321 ) 322 ) 323 ?> 324 ">Migrate</a> 325 </div> 326 <?php 327 } 328 ); 329 330 return false; 331 } 261 332 } -
shopping-feed/tags/6.1.0/src/ShoppingFeedHelper.php
r2560053 r2670662 7 7 8 8 use ShoppingFeed\ShoppingFeedWC\Admin\Options; 9 use ShoppingFeed\ShoppingFeedWC\Sdk\Sdk;10 9 use ShoppingFeed\ShoppingFeedWC\Url\Rewrite; 11 10 use WC_Logger; … … 141 140 142 141 /** 143 * Set SF token after connection144 *145 * @param $token146 *147 */148 public static function set_sf_token( $token ) {149 $options = self::get_sf_account_options();150 $options['token'] = $token;151 152 update_option( Options::SF_ACCOUNT_OPTIONS, $options );153 }154 155 /**156 142 * Return SF Configuration for Account 157 * @return mixed|void143 * @return array 158 144 */ 159 145 public static function get_sf_account_options() { 160 return get_option( Options::SF_ACCOUNT_OPTIONS ); 161 } 162 163 /** 164 * Reset password if bad 165 * 166 * @param $token 167 * 168 */ 169 public static function clean_password() { 170 $options = self::get_sf_account_options(); 171 if ( isset( $options ) && isset( $options['password'] ) ) { 172 unset( $options['password'] ); 173 } 174 175 update_option( Options::SF_ACCOUNT_OPTIONS, $options ); 146 return get_option( Options::SF_ACCOUNT_OPTIONS, array() ); 147 } 148 149 150 /** 151 * Set SF Configuration for Account 152 * @return bool 153 */ 154 public static function set_sf_account_options( $option ) { 155 return update_option( Options::SF_ACCOUNT_OPTIONS, $option ); 156 } 157 158 /** 159 * @param $account_id 160 * @psalm-suppress all 161 * @return array 162 */ 163 public static function get_sf_account_credentials( $account_id ) { 164 $account_options = self::get_sf_account_options(); 165 $index = array_search( (int) $account_id, array_column( $account_options, 'sf_store_id' ), true ); 166 if ( false === $index || empty( $account_options[ $index ] ) ) { 167 return array(); 168 } 169 170 return $account_options[ $index ]; 176 171 } 177 172 … … 566 561 567 562 /** 568 * @return bool569 */570 public static function is_authenticated() {571 $sdk = Sdk::get_instance();572 if ( empty( $sdk ) ) {573 return false;574 }575 576 return $sdk->authenticate();577 }578 579 /**580 563 * Add filter for category taxonomy 581 564 * default: product_cat … … 662 645 /** 663 646 * Check if a running generation process 647 * 648 * @param $group 649 * 664 650 * @return bool 665 651 */ 666 public static function generation_process_running() {667 $process = self::get_running_ generation_feed_process();652 public static function is_process_running( $group ) { 653 $process = self::get_running_process( $group ); 668 654 669 655 return ! empty( $process ); … … 672 658 /** 673 659 * Get running process list 660 * 661 * @param string $group 662 * 674 663 * @return array|int 675 664 */ 676 public static function get_running_ generation_feed_process() {665 public static function get_running_process( $group ) { 677 666 $action_scheduler = \ActionScheduler::store(); 678 667 679 668 return $action_scheduler->query_actions( 680 669 array( 681 'group' => 'sf_feed_generation_process',670 'group' => $group, 682 671 'status' => $action_scheduler::STATUS_PENDING, 683 672 ) … … 685 674 } 686 675 687 public static function clean_generation_process_running() { 676 /** 677 * @param string $group 678 */ 679 public static function clean_process_running( $group ) { 688 680 try { 689 \ActionScheduler::store()->cancel_actions_by_group( 'sf_feed_generation_process');681 \ActionScheduler::store()->cancel_actions_by_group( $group ); 690 682 } catch ( \Exception $exception ) { 691 683 self::get_logger()->error( … … 732 724 733 725 /** 726 * Check if new customer 727 * @return bool 728 */ 729 public static function sf_new_customer() { 730 return empty( get_option( Options::SF_ACCOUNT_OPTIONS ) ) && 731 empty( get_option( Options::SF_FEED_OPTIONS ) ) && 732 empty( get_option( Options::SF_SHIPPING_OPTIONS ) ) && 733 empty( get_option( Options::SF_ORDERS_OPTIONS ) ); 734 } 735 736 /** 734 737 * Singleton instance can't be cloned. 735 738 */ … … 742 745 private function __wakeup() { 743 746 } 747 748 /** 749 * Check if we have an upgrade 750 * @return bool 751 */ 752 public static function sf_has_upgrade() { 753 754 $db_version = get_option( SF_DB_VERSION_SLUG ); 755 756 return empty( $db_version ) || version_compare( $db_version, SF_DB_VERSION, '<' ); 757 } 758 759 /** 760 * Check if we have a running upgrade 761 * @return bool 762 */ 763 public static function is_upgrade_running() { 764 return ! empty( get_option( SF_UPGRADE_RUNNING ) ); 765 } 766 767 /* 768 * End upgrade 769 */ 770 public static function end_upgrade() { 771 delete_option( SF_UPGRADE_RUNNING ); 772 update_option( SF_DB_VERSION_SLUG, SF_DB_VERSION ); 773 } 744 774 } -
shopping-feed/tags/6.1.0/vendor/autoload.php
r2613147 r2670662 5 5 require_once __DIR__ . '/composer/autoload_real.php'; 6 6 7 return ComposerAutoloaderInit 8e1243f94001ab8dc300d6b62efdcaf0::getLoader();7 return ComposerAutoloaderInit0002ac7dfac052b9a9cc79f1494358a4::getLoader(); -
shopping-feed/tags/6.1.0/vendor/composer/ClassLoader.php
r2602861 r2670662 150 150 /** 151 151 * @return string[] Array of classname => path 152 * @psalm- vararray<string, string>152 * @psalm-return array<string, string> 153 153 */ 154 154 public function getClassMap() -
shopping-feed/tags/6.1.0/vendor/composer/InstalledVersions.php
r2602861 r2670662 25 25 class InstalledVersions 26 26 { 27 /** 28 * @var mixed[]|null 29 * @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null 30 */ 27 31 private static $installed; 32 33 /** 34 * @var bool|null 35 */ 28 36 private static $canGetVendors; 37 38 /** 39 * @var array[] 40 * @psalm-var array<string, array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}> 41 */ 29 42 private static $installedByVendor = array(); 30 43 -
shopping-feed/tags/6.1.0/vendor/composer/autoload_real.php
r2613147 r2670662 3 3 // autoload_real.php @generated by Composer 4 4 5 class ComposerAutoloaderInit 8e1243f94001ab8dc300d6b62efdcaf05 class ComposerAutoloaderInit0002ac7dfac052b9a9cc79f1494358a4 6 6 { 7 7 private static $loader; … … 23 23 } 24 24 25 spl_autoload_register(array('ComposerAutoloaderInit 8e1243f94001ab8dc300d6b62efdcaf0', 'loadClassLoader'), true, true);25 spl_autoload_register(array('ComposerAutoloaderInit0002ac7dfac052b9a9cc79f1494358a4', 'loadClassLoader'), true, true); 26 26 self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__))); 27 spl_autoload_unregister(array('ComposerAutoloaderInit 8e1243f94001ab8dc300d6b62efdcaf0', 'loadClassLoader'));27 spl_autoload_unregister(array('ComposerAutoloaderInit0002ac7dfac052b9a9cc79f1494358a4', 'loadClassLoader')); 28 28 29 29 $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); … … 31 31 require __DIR__ . '/autoload_static.php'; 32 32 33 call_user_func(\Composer\Autoload\ComposerStaticInit 8e1243f94001ab8dc300d6b62efdcaf0::getInitializer($loader));33 call_user_func(\Composer\Autoload\ComposerStaticInit0002ac7dfac052b9a9cc79f1494358a4::getInitializer($loader)); 34 34 } else { 35 35 $map = require __DIR__ . '/autoload_namespaces.php'; … … 52 52 53 53 if ($useStaticLoader) { 54 $includeFiles = Composer\Autoload\ComposerStaticInit 8e1243f94001ab8dc300d6b62efdcaf0::$files;54 $includeFiles = Composer\Autoload\ComposerStaticInit0002ac7dfac052b9a9cc79f1494358a4::$files; 55 55 } else { 56 56 $includeFiles = require __DIR__ . '/autoload_files.php'; 57 57 } 58 58 foreach ($includeFiles as $fileIdentifier => $file) { 59 composerRequire 8e1243f94001ab8dc300d6b62efdcaf0($fileIdentifier, $file);59 composerRequire0002ac7dfac052b9a9cc79f1494358a4($fileIdentifier, $file); 60 60 } 61 61 … … 64 64 } 65 65 66 function composerRequire8e1243f94001ab8dc300d6b62efdcaf0($fileIdentifier, $file) 66 /** 67 * @param string $fileIdentifier 68 * @param string $file 69 * @return void 70 */ 71 function composerRequire0002ac7dfac052b9a9cc79f1494358a4($fileIdentifier, $file) 67 72 { 68 73 if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { 74 $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; 75 69 76 require $file; 70 71 $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;72 77 } 73 78 } -
shopping-feed/tags/6.1.0/vendor/composer/autoload_static.php
r2613147 r2670662 5 5 namespace Composer\Autoload; 6 6 7 class ComposerStaticInit 8e1243f94001ab8dc300d6b62efdcaf07 class ComposerStaticInit0002ac7dfac052b9a9cc79f1494358a4 8 8 { 9 9 public static $files = array ( … … 439 439 { 440 440 return \Closure::bind(function () use ($loader) { 441 $loader->prefixLengthsPsr4 = ComposerStaticInit 8e1243f94001ab8dc300d6b62efdcaf0::$prefixLengthsPsr4;442 $loader->prefixDirsPsr4 = ComposerStaticInit 8e1243f94001ab8dc300d6b62efdcaf0::$prefixDirsPsr4;443 $loader->classMap = ComposerStaticInit 8e1243f94001ab8dc300d6b62efdcaf0::$classMap;441 $loader->prefixLengthsPsr4 = ComposerStaticInit0002ac7dfac052b9a9cc79f1494358a4::$prefixLengthsPsr4; 442 $loader->prefixDirsPsr4 = ComposerStaticInit0002ac7dfac052b9a9cc79f1494358a4::$prefixDirsPsr4; 443 $loader->classMap = ComposerStaticInit0002ac7dfac052b9a9cc79f1494358a4::$classMap; 444 444 445 445 }, null, ClassLoader::class); -
shopping-feed/tags/6.1.0/vendor/composer/installed.php
r2613147 r2670662 1 1 <?php return array( 2 2 'root' => array( 3 'pretty_version' => '6. 0.33',4 'version' => '6. 0.33.0',3 'pretty_version' => '6.1.0', 4 'version' => '6.1.0.0', 5 5 'type' => 'wordpress-plugin', 6 6 'install_path' => __DIR__ . '/../../', 7 7 'aliases' => array(), 8 'reference' => ' b54ebdf093f62b8a77538414cf5a4eb070cd1bb5',8 'reference' => '7457e98e9f4b6982416834d213cea5359612cfd9', 9 9 'name' => 'shoppingfeed/shoppingfeed', 10 10 'dev' => false, … … 102 102 ), 103 103 'shoppingfeed/shoppingfeed' => array( 104 'pretty_version' => '6. 0.33',105 'version' => '6. 0.33.0',104 'pretty_version' => '6.1.0', 105 'version' => '6.1.0.0', 106 106 'type' => 'wordpress-plugin', 107 107 'install_path' => __DIR__ . '/../../', 108 108 'aliases' => array(), 109 'reference' => ' b54ebdf093f62b8a77538414cf5a4eb070cd1bb5',109 'reference' => '7457e98e9f4b6982416834d213cea5359612cfd9', 110 110 'dev_requirement' => false, 111 111 ), -
shopping-feed/trunk/assets/css/app.css
r2384546 r2670662 71 71 cursor: inherit; } 72 72 73 .sf__inline { 74 display: inline-block; 75 margin-right: 0; } 76 77 .sf__table tr:first-child button { 78 display: none; } 79 80 .sf__table td { 81 padding-left: 0; } 82 73 83 .sf__logo { 74 84 overflow: hidden; … … 95 105 background-color: #19a088; } 96 106 97 .sf__button__ logout.button {107 .sf__button__secondary.button, .sf__button__logout.button { 98 108 color: #fff; 99 109 text-transform: uppercase; 100 110 border-color: #632F8E; 101 111 background-color: #632F8E; } 102 .sf__button__ logout.button:hover, .sf__button__logout.button:active, .sf__button__logout.button:focus {112 .sf__button__secondary.button:hover, .sf__button__secondary.button:active, .sf__button__secondary.button:focus, .sf__button__logout.button:hover, .sf__button__logout.button:active, .sf__button__logout.button:focus { 103 113 color: #fff; 104 114 border-color: #56297b; … … 222 232 flex-basis: 33%; } } 223 233 224 /*# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBwLmNzcyIsInNvdXJjZXMiOlsiYXBwLnNjc3MiLCJtYWluL19taXhpbnMuc2NzcyIsIm1haW4vX2NvbG9ycy5zY3NzIiwibXVsdGkvX211bHRpLnNjc3MiLCJtYWluL19zZi5zY3NzIl0sInNvdXJjZXNDb250ZW50IjpbIkBpbXBvcnQgXCJtYWluL21peGluc1wiO1xuQGltcG9ydCBcIm1haW4vY29sb3JzXCI7XG5AaW1wb3J0IFwibXVsdGkvbXVsdGlcIjtcbkBpbXBvcnQgXCJtYWluL3NmXCI7IiwiLy8gQm91cmJvbidzIGVzc2VudGlhbHMgbWl4aW5zXG4kZW0tYmFzZTogMTZweCAhZGVmYXVsdDtcbi8vIFN0cmlwIHVuaXRzXG5AZnVuY3Rpb24gc3RyaXAtdW5pdHMoJHZhbHVlKSB7XG5cdEByZXR1cm4gKCR2YWx1ZSAvICgkdmFsdWUgKiAwICsgMSkpO1xufVxuLy8gUFggdG8gRU1cbkBmdW5jdGlvbiBlbSgkcHh2YWwsICRiYXNlOiAkZW0tYmFzZSkge1xuXHRAaWYgbm90IHVuaXRsZXNzKCRweHZhbCkge1xuXHQgICRweHZhbDogc3RyaXAtdW5pdHMoJHB4dmFsKTtcblx0fVxuXHRAaWYgbm90IHVuaXRsZXNzKCRiYXNlKSB7XG5cdCAgJGJhc2U6IHN0cmlwLXVuaXRzKCRiYXNlKTtcblx0fVxuXHRAcmV0dXJuICgkcHh2YWwgLyAkYmFzZSkgKiAxZW07XG59XG4vL0JyZWFrcG9pbnRzXG4kYnJlYWtwb2ludHM6IChcbiAgICB4c206IGVtKDQ4MCksXG4gICAgc206IGVtKDc2OCksXG4gICAgbWQ6IGVtKDEwMjQpLFxuICAgIGxnOiBlbSgxMjYwKSxcbiAgICB4bGc6IGVtKDE0NDApXG4pO1xuXG5AbWl4aW4gYnJlYWtwb2ludHMoJGJyZWFrcG9pbnQpIHtcbiAgICBAbWVkaWEgc2NyZWVuIGFuZCAobWluLXdpZHRoOiBtYXAtZ2V0KCRtYXA6ICRicmVha3BvaW50cywgJGtleTogJGJyZWFrcG9pbnQpKSB7XG4gICAgICAgIEBjb250ZW50O1xuICAgIH1cbn1cbi8vIEhvdmVyIEFjdGl2ZSBGb2N1cyBwc2V1ZG8gc2VsZWN0b3IgbWl4aW5cbkBtaXhpbiBob3ZlciB7XG5cdCY6aG92ZXIsICY6YWN0aXZlLCAmOmZvY3VzIHtcblx0XHRAY29udGVudDtcblx0fVxufVxuLy8gU21vb3RoIHRleHRcbkBtaXhpbiBzbW9vdGhUZXh0IHtcblx0LXdlYmtpdC1mb250LXNtb290aGluZzogYW50aWFsaWFzZWQ7XG4gICAgLW1vei1vc3gtZm9udC1zbW9vdGhpbmc6IGdyYXlzY2FsZTtcbn0iLCIkd2hpdGU6ICNmZmY7XG4kYmxhY2s6ICMwMDA7XG4kcHJpbWFyeTogIzYzMkY4RTtcbiRzZWNvbmRhcnk6ICMxQ0I2OUI7XG4kdGV4dGNvbG9yOiAjMjMyODJEO1xuJGdyYXk6ICM5RTlFOUU7XG4kYmx1ZTogIzA0Mjc0RDtcbiRwaW5rOiAjRTkxRTYzO1xuIiwiLm11bHRpLXdyYXBwZXIge1xuICAgIGJvcmRlcjogMXB4IHNvbGlkICNjY2M7XG4gICAgYm9yZGVyLXJhZGl1czogM3B4O1xuICAgIHdpZHRoOiAxMDAlO1xufVxuXG4ubXVsdGktd3JhcHBlciAubm9uLXNlbGVjdGVkLXdyYXBwZXIsXG4ubXVsdGktd3JhcHBlciAuc2VsZWN0ZWQtd3JhcHBlciB7XG4gICAgYm94LXNpemluZzogYm9yZGVyLWJveDtcbiAgICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7XG4gICAgaGVpZ2h0OiAyMDBweDtcbiAgICBvdmVyZmxvdy15OiBzY3JvbGw7XG4gICAgcGFkZGluZzogMTBweDtcbiAgICB2ZXJ0aWNhbC1hbGlnbjogdG9wO1xuICAgIHdpZHRoOiA1MCU7XG59XG5cbi5tdWx0aS13cmFwcGVyIC5ub24tc2VsZWN0ZWQtd3JhcHBlciB7XG4gICAgYmFja2dyb3VuZDogI2ZhZmFmYTtcbiAgICBib3JkZXItcmlnaHQ6IDFweCBzb2xpZCAjY2NjO1xufVxuXG4ubXVsdGktd3JhcHBlciAuc2VsZWN0ZWQtd3JhcHBlciB7XG4gICAgYmFja2dyb3VuZDogI2ZmZjtcbn1cblxuLm11bHRpLXdyYXBwZXIgLmhlYWRlciB7XG4gICAgY29sb3I6ICM0ZjRmNGY7XG4gICAgY3Vyc29yOiBkZWZhdWx0O1xuICAgIGZvbnQtd2VpZ2h0OiBib2xkO1xuICAgIG1hcmdpbi1ib3R0b206IDVweDtcbiAgICBwYWRkaW5nOiA1cHggMTBweDtcbn1cblxuLm11bHRpLXdyYXBwZXIgLml0ZW0ge1xuICAgIGN1cnNvcjogcG9pbnRlcjtcbiAgICBkaXNwbGF5OiBibG9jaztcbiAgICBwYWRkaW5nOiA1cHggMTBweDtcbn1cblxuLm11bHRpLXdyYXBwZXIgLml0ZW06aG92ZXIge1xuICAgIGJhY2tncm91bmQ6ICNlY2VjZWM7XG4gICAgYm9yZGVyLXJhZGl1czogMnB4O1xufVxuXG4ubXVsdGktd3JhcHBlciAuaXRlbS1ncm91cCB7XG4gICAgcGFkZGluZzogNXB4IDEwcHg7XG59XG5cbi5tdWx0aS13cmFwcGVyIC5pdGVtLWdyb3VwIC5ncm91cC1sYWJlbCB7XG4gICAgZGlzcGxheTogYmxvY2s7XG4gICAgZm9udC1zaXplOiAwLjg3NXJlbTtcbiAgICBvcGFjaXR5OiAwLjU7XG4gICAgcGFkZGluZzogNXB4IDA7XG59XG5cbi5tdWx0aS13cmFwcGVyIC5zZWFyY2gtaW5wdXQge1xuICAgIGJvcmRlcjogMDtcbiAgICBib3JkZXItYm90dG9tOiAxcHggc29saWQgI2NjYztcbiAgICBib3JkZXItcmFkaXVzOiAwO1xuICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgIGZvbnQtc2l6ZTogMWVtO1xuICAgIG1hcmdpbjogMDtcbiAgICBvdXRsaW5lOiAwO1xuICAgIHBhZGRpbmc6IDEwcHggMjBweDtcbiAgICB3aWR0aDogMTAwJTtcbiAgICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xufVxuXG4ubXVsdGktd3JhcHBlciAubm9uLXNlbGVjdGVkLXdyYXBwZXIgLml0ZW0uc2VsZWN0ZWQge1xuICAgIG9wYWNpdHk6IDAuNTtcbn1cblxuLm11bHRpLXdyYXBwZXIgLm5vbi1zZWxlY3RlZC13cmFwcGVyIC5pdGVtLmRpc2FibGVkLFxuLm11bHRpLXdyYXBwZXIgLnNlbGVjdGVkLXdyYXBwZXIgLml0ZW0uZGlzYWJsZWQge1xuICAgIG9wYWNpdHk6IDAuNTtcbiAgICB0ZXh0LWRlY29yYXRpb246IGxpbmUtdGhyb3VnaDtcbn1cblxuLm11bHRpLXdyYXBwZXIgLm5vbi1zZWxlY3RlZC13cmFwcGVyIC5pdGVtLmRpc2FibGVkOmhvdmVyLFxuLm11bHRpLXdyYXBwZXIgLnNlbGVjdGVkLXdyYXBwZXIgLml0ZW0uZGlzYWJsZWQ6aG92ZXIge1xuICAgIGJhY2tncm91bmQ6IGluaGVyaXQ7XG4gICAgY3Vyc29yOiBpbmhlcml0O1xufSIsIi5zZiB7XG5cbiAgJl9f bG9nbyB7XG4gICAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgICB0ZXh0LWluZGVudDogLTk5OTk5cHg7XG4gICAgYmFja2dyb3VuZDogdXJsKFwiLi4vaW1hZ2VzL3NmX2xvZ28uc3ZnXCIpIG5vLXJlcGVhdCBjZW50ZXIgbGVmdDtcbiAgICBiYWNrZ3JvdW5kLXNpemU6IGNvbnRhaW47XG4gICAgbWF4LXdpZHRoOiAyOTdweDtcbiAgICBoZWlnaHQ6IDUzcHg7XG4gIH1cblxuICAmX192ZXJzaW9uIHtcbiAgICBjb2xvcjogJGdyYXk7XG4gICAgZm9udC1zaXplOiAxMnB4O1xuICAgIGxpbmUtaGVpZ2h0OiAxN3B4O1xuICAgIG1hcmdpbjogNXB4IDA7XG4gIH1cblxuICAmX19idXR0b24uYnV0dG9uIHtcbiAgICBjb2xvcjogJHdoaXRlO1xuICAgIHRleHQtdHJhbnNmb3JtOiB1cHBlcmNhc2U7XG4gICAgYm9yZGVyLWNvbG9yOiAkc2Vjb25kYXJ5O1xuICAgIGJhY2tncm91bmQtY29sb3I6ICRzZWNvbmRhcnk7XG4gICAgQGluY2x1ZGUgaG92ZXIge1xuICAgICAgY29sb3I6ICR3aGl0ZTtcbiAgICAgIGJvcmRlci1jb2xvcjogZGFya2VuKCRzZWNvbmRhcnksIDUlKTtcbiAgICAgIGJhY2tncm91bmQtY29sb3I6IGRhcmtlbigkc2Vjb25kYXJ5LCA1JSk7XG4gICAgfVxuICB9XG5cbiAgJl9fYnV0dG9uX19sb2dvdXQuYnV0dG9uIHtcbiAgICBjb2xvcjogJHdoaXRlO1xuICAgIHRleHQtdHJhbnNmb3JtOiB1cHBlcmNhc2U7XG4gICAgYm9yZGVyLWNvbG9yOiAkcHJpbWFyeTtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAkcHJpbWFyeTtcbiAgICBAaW5jbHVkZSBob3ZlciB7XG4gICAgICBjb2xvcjogJHdoaXRlO1xuICAgICAgYm9yZGVyLWNvbG9yOiBkYXJrZW4oJHByaW1hcnksIDUlKTtcbiAgICAgIGJhY2tncm91bmQtY29sb3I6IGRhcmtlbigkcHJpbWFyeSwgNSUpO1xuICAgIH1cbiAgfVxuXG4gICZfX3JlcXVpcmVtZW50cyB7XG4gICAgLnN1Y2Nlc3MsXG4gICAgLmZhaWxlZCB7XG4gICAgICBAaW5jbHVkZSBzbW9vdGhUZXh0O1xuICAgICAgcG9zaXRpb246IHJlbGF0aXZlO1xuICAgICAgcGFkZGluZy1sZWZ0OiAyNnB4O1xuICAgICAgY29sb3I6ICR0ZXh0Y29sb3I7XG5cbiAgICAgICY6YmVmb3JlIHtcbiAgICAgICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgICAgICB0b3A6IDA7XG4gICAgICAgIGxlZnQ6IDA7XG4gICAgICAgIGZvbnQtZmFtaWx5OiBkYXNoaWNvbnM7XG4gICAgICAgIGNvbnRlbnQ6IFwiXFxmMTQ3XCI7XG4gICAgICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgICAgICB3aWR0aDogMTZweDtcbiAgICAgICAgaGVpZ2h0OiAxNnB4O1xuICAgICAgICBsaW5lLWhlaWdodDogMTZweDtcbiAgICAgICAgZm9udC1zaXplOiAxNHB4O1xuICAgICAgICBib3JkZXItcmFkaXVzOiA1MCU7XG4gICAgICAgIHRleHQtYWxpZ246IGNlbnRlcjtcbiAgICAgICAgY29sb3I6ICR3aGl0ZTtcbiAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogJHNlY29uZGFyeTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAuZmFpbGVkIHtcbiAgICAgIGNvbG9yOiAkdGV4dGNvbG9yO1xuXG4gICAgICAmOmJlZm9yZSB7XG4gICAgICAgIGNvbnRlbnQ6IFwiXFxmMzM1XCI7XG4gICAgICAgIGJhY2tncm91bmQtY29sb3I6ICRncmF5O1xuICAgICAgfVxuICAgIH1cblxuICB9XG5cbiAgJl9faGVybyB7XG4gICAgcG9zaXRpb246IHJlbGF0aXZlO1xuICAgIGJvcmRlcjogMDtcbiAgICBib3JkZXItcmFkaXVzOiAycHg7XG4gICAgYmFja2dyb3VuZDogbGluZWFyLWdyYWRpZW50KDE4MGRlZywgIzAzMjc0RCAwJSwgIzUyMzA4MSAxMDAlKTtcbiAgICBiYWNrZ3JvdW5kLXNpemU6IGNvdmVyO1xuICAgIHBhZGRpbmc6IDMwcHg7XG5cbiAgICAmOmJlZm9yZSB7XG4gICAgICBjb250ZW50OiBcIlwiO1xuICAgICAgZGlzcGxheTogYmxvY2s7XG4gICAgICB6LWluZGV4OiAxO1xuICAgICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgICAgdG9wOiAwO1xuICAgICAgcmlnaHQ6IDMwcHg7XG4gICAgICBib3R0b206IDA7XG4gICAgICBsZWZ0OiAwO1xuICAgICAgYmFja2dyb3VuZDogdXJsKFwiLi4vaW1hZ2VzL3NmX21hcmtldGluZy5zdmdcIikgbm8tcmVwZWF0IGNlbnRlciByaWdodDtcbiAgICAgIHBvaW50ZXItZXZlbnRzOiBub25lO1xuICAgIH1cbiAgICAmLS10aXRsZXtcbiAgICAgIGZvbnQtc2l6ZTogMTZweDtcbiAgICAgIGxpbmUtaGVpZ2h0OiAyMnB4O1xuICAgICAgcGFkZGluZy1yaWdodDogMzBweDtcbiAgICAgIGNvbG9yOiAkd2hpdGU7XG4gICAgICBmb250LXdlaWdodDogYm9sZDtcbiAgICAgIG1hcmdpbi1ib3R0b206IDE1cHg7XG4gICAgfVxuICB9XG5cbiAgJl9fbWFya2V0aW5nIHtcbiAgICBib3JkZXItbGVmdDogMXB4IHNvbGlkICRwcmltYXJ5O1xuICAgIHBhZGRpbmctbGVmdDogMjZweDtcblxuICAgICYtLXRpdGxle1xuICAgICAgY29sb3I6ICRwcmltYXJ5O1xuICAgICAgZm9udC1zaXplOiAxLjVlbTtcbiAgICAgIG1hcmdpbjogMDtcbiAgICAgIG1hcmdpbi10b3A6IDFlbTtcbiAgICB9XG4gICAgJi0tc3VidGl0bGV7XG4gICAgICBjb2xvcjogJGdyYXk7XG4gICAgICBmb250LXNpemU6IDEwcHg7XG4gICAgICB0ZXh0LXRyYW5zZm9ybTogdXBwZXJjYXNlO1xuICAgICAgbGV0dGVyLXNwYWNpbmc6IDMuMzNweDtcbiAgICAgIG1hcmdpbjogMDtcbiAgICAgIHBhZGRpbmctdG9wOiA1cHg7XG4gICAgfVxuICAgICYtLXRleHR7XG4gICAgICBjb2xvcjogJHRleHRjb2xvcjtcbiAgICAgIGZvbnQtc2l6ZTogMTJweDtcbiAgICAgIGxldHRlci1zcGFjaW5nOiAwO1xuICAgICAgbGluZS1oZWlnaHQ6IDE3cHg7XG4gICAgfVxuXG4gICAgJi0tZG93bmxvYWQge1xuICAgICAgcGFkZGluZzogMWVtIDA7XG5cbiAgICAgIGxpIHtcbiAgICAgICAgbGluZS1oZWlnaHQ6IDEuNWVtO1xuICAgICAgfVxuXG4gICAgICBhIHtcbiAgICAgICAgQGluY2x1ZGUgc21vb3RoVGV4dDtcbiAgICAgICAgcG9zaXRpb246IHJlbGF0aXZlO1xuICAgICAgICBwYWRkaW5nLWxlZnQ6IDI2cHg7XG4gICAgICAgIGNvbG9yOiAkYmx1ZTtcbiAgICAgICAgZm9udC13ZWlnaHQ6IGJvbGQ7XG5cbiAgICAgICAgJjpiZWZvcmUge1xuICAgICAgICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICAgICAgICB0b3A6IDA7XG4gICAgICAgICAgbGVmdDogMDtcbiAgICAgICAgICBmb250LWZhbWlseTogZGFzaGljb25zO1xuICAgICAgICAgIGNvbnRlbnQ6IFwiXFxmMzQ2XCI7XG4gICAgICAgICAgZGlzcGxheTogYmxvY2s7XG4gICAgICAgICAgd2lkdGg6IDE2cHg7XG4gICAgICAgICAgaGVpZ2h0OiAxNnB4O1xuICAgICAgICAgIGxpbmUtaGVpZ2h0OiAxNnB4O1xuICAgICAgICAgIGZvbnQtc2l6ZTogMTRweDtcbiAgICAgICAgICBib3JkZXItcmFkaXVzOiA1MCU7XG4gICAgICAgICAgdGV4dC1hbGlnbjogY2VudGVyO1xuICAgICAgICAgIGNvbG9yOiAkd2hpdGU7XG4gICAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogJHByaW1hcnk7XG4gICAgICAgIH1cblxuICAgICAgICAmOmhvdmVyIHtcbiAgICAgICAgICBjb2xvcjogJHByaW1hcnk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAmX19wbHVnaW57XG4gICAgLnNmX19ub3RpY2UtLXN0YXJ0IGF7XG4gICAgICBkaXNwbGF5OiBub25lO1xuICAgIH1cbiAgfVxuXG5cbiAgQGluY2x1ZGUgYnJlYWtwb2ludHMobWQpIHtcbiAgICAmX19jb2x1bW5zIHtcbiAgICAgIGRpc3BsYXk6IGZsZXg7XG4gICAgICBmbGV4LXdyYXA6IHdyYXA7XG4gICAgfVxuICAgICZfX2NvbHVtbiB7XG4gICAgICBmbGV4LWJhc2lzOiA2NiU7XG5cbiAgICAgICY6bGFzdC1jaGlsZCB7XG4gICAgICAgIGZsZXgtYmFzaXM6IDMzJTtcbiAgICAgIH1cbiAgICB9XG5cbiAgfVxufVxuIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBR0FBLEFBQUEsY0FBYyxDQUFDO0VBQ1gsTUFBTSxFQUFFLGNBQWM7RUFDdEIsYUFBYSxFQUFFLEdBQUc7RUFDbEIsS0FBSyxFQUFFLElBQUksR0FDZDs7QUFFRCxBQUFBLGNBQWMsQ0FBQyxxQkFBcUI7QUFDcEMsY0FBYyxDQUFDLGlCQUFpQixDQUFDO0VBQzdCLFVBQVUsRUFBRSxVQUFVO0VBQ3RCLE9BQU8sRUFBRSxZQUFZO0VBQ3JCLE1BQU0sRUFBRSxLQUFLO0VBQ2IsVUFBVSxFQUFFLE1BQU07RUFDbEIsT0FBTyxFQUFFLElBQUk7RUFDYixjQUFjLEVBQUUsR0FBRztFQUNuQixLQUFLLEVBQUUsR0FBRyxHQUNiOztBQUVELEFBQUEsY0FBYyxDQUFDLHFCQUFxQixDQUFDO0VBQ2pDLFVBQVUsRUFBRSxPQUFPO0VBQ25CLFlBQVksRUFBRSxjQUFjLEdBQy9COztBQUVELEFBQUEsY0FBYyxDQUFDLGlCQUFpQixDQUFDO0VBQzdCLFVBQVUsRUFBRSxJQUFJLEdBQ25COztBQUVELEFBQUEsY0FBYyxDQUFDLE9BQU8sQ0FBQztFQUNuQixLQUFLLEVBQUUsT0FBTztFQUNkLE1BQU0sRUFBRSxPQUFPO0VBQ2YsV0FBVyxFQUFFLElBQUk7RUFDakIsYUFBYSxFQUFFLEdBQUc7RUFDbEIsT0FBTyxFQUFFLFFBQVEsR0FDcEI7O0FBRUQsQUFBQSxjQUFjLENBQUMsS0FBSyxDQUFDO0VBQ2pCLE1BQU0sRUFBRSxPQUFP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*/234 /*# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXBwLmNzcyIsInNvdXJjZXMiOlsiYXBwLnNjc3MiLCJtYWluL19taXhpbnMuc2NzcyIsIm1haW4vX2NvbG9ycy5zY3NzIiwibXVsdGkvX211bHRpLnNjc3MiLCJtYWluL19zZi5zY3NzIl0sInNvdXJjZXNDb250ZW50IjpbIkBpbXBvcnQgXCJtYWluL21peGluc1wiO1xuQGltcG9ydCBcIm1haW4vY29sb3JzXCI7XG5AaW1wb3J0IFwibXVsdGkvbXVsdGlcIjtcbkBpbXBvcnQgXCJtYWluL3NmXCI7IiwiLy8gQm91cmJvbidzIGVzc2VudGlhbHMgbWl4aW5zXG4kZW0tYmFzZTogMTZweCAhZGVmYXVsdDtcbi8vIFN0cmlwIHVuaXRzXG5AZnVuY3Rpb24gc3RyaXAtdW5pdHMoJHZhbHVlKSB7XG5cdEByZXR1cm4gKCR2YWx1ZSAvICgkdmFsdWUgKiAwICsgMSkpO1xufVxuLy8gUFggdG8gRU1cbkBmdW5jdGlvbiBlbSgkcHh2YWwsICRiYXNlOiAkZW0tYmFzZSkge1xuXHRAaWYgbm90IHVuaXRsZXNzKCRweHZhbCkge1xuXHQgICRweHZhbDogc3RyaXAtdW5pdHMoJHB4dmFsKTtcblx0fVxuXHRAaWYgbm90IHVuaXRsZXNzKCRiYXNlKSB7XG5cdCAgJGJhc2U6IHN0cmlwLXVuaXRzKCRiYXNlKTtcblx0fVxuXHRAcmV0dXJuICgkcHh2YWwgLyAkYmFzZSkgKiAxZW07XG59XG4vL0JyZWFrcG9pbnRzXG4kYnJlYWtwb2ludHM6IChcbiAgICB4c206IGVtKDQ4MCksXG4gICAgc206IGVtKDc2OCksXG4gICAgbWQ6IGVtKDEwMjQpLFxuICAgIGxnOiBlbSgxMjYwKSxcbiAgICB4bGc6IGVtKDE0NDApXG4pO1xuXG5AbWl4aW4gYnJlYWtwb2ludHMoJGJyZWFrcG9pbnQpIHtcbiAgICBAbWVkaWEgc2NyZWVuIGFuZCAobWluLXdpZHRoOiBtYXAtZ2V0KCRtYXA6ICRicmVha3BvaW50cywgJGtleTogJGJyZWFrcG9pbnQpKSB7XG4gICAgICAgIEBjb250ZW50O1xuICAgIH1cbn1cbi8vIEhvdmVyIEFjdGl2ZSBGb2N1cyBwc2V1ZG8gc2VsZWN0b3IgbWl4aW5cbkBtaXhpbiBob3ZlciB7XG5cdCY6aG92ZXIsICY6YWN0aXZlLCAmOmZvY3VzIHtcblx0XHRAY29udGVudDtcblx0fVxufVxuLy8gU21vb3RoIHRleHRcbkBtaXhpbiBzbW9vdGhUZXh0IHtcblx0LXdlYmtpdC1mb250LXNtb290aGluZzogYW50aWFsaWFzZWQ7XG4gICAgLW1vei1vc3gtZm9udC1zbW9vdGhpbmc6IGdyYXlzY2FsZTtcbn0iLCIkd2hpdGU6ICNmZmY7XG4kYmxhY2s6ICMwMDA7XG4kcHJpbWFyeTogIzYzMkY4RTtcbiRzZWNvbmRhcnk6ICMxQ0I2OUI7XG4kdGV4dGNvbG9yOiAjMjMyODJEO1xuJGdyYXk6ICM5RTlFOUU7XG4kYmx1ZTogIzA0Mjc0RDtcbiRwaW5rOiAjRTkxRTYzO1xuIiwiLm11bHRpLXdyYXBwZXIge1xuICAgIGJvcmRlcjogMXB4IHNvbGlkICNjY2M7XG4gICAgYm9yZGVyLXJhZGl1czogM3B4O1xuICAgIHdpZHRoOiAxMDAlO1xufVxuXG4ubXVsdGktd3JhcHBlciAubm9uLXNlbGVjdGVkLXdyYXBwZXIsXG4ubXVsdGktd3JhcHBlciAuc2VsZWN0ZWQtd3JhcHBlciB7XG4gICAgYm94LXNpemluZzogYm9yZGVyLWJveDtcbiAgICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7XG4gICAgaGVpZ2h0OiAyMDBweDtcbiAgICBvdmVyZmxvdy15OiBzY3JvbGw7XG4gICAgcGFkZGluZzogMTBweDtcbiAgICB2ZXJ0aWNhbC1hbGlnbjogdG9wO1xuICAgIHdpZHRoOiA1MCU7XG59XG5cbi5tdWx0aS13cmFwcGVyIC5ub24tc2VsZWN0ZWQtd3JhcHBlciB7XG4gICAgYmFja2dyb3VuZDogI2ZhZmFmYTtcbiAgICBib3JkZXItcmlnaHQ6IDFweCBzb2xpZCAjY2NjO1xufVxuXG4ubXVsdGktd3JhcHBlciAuc2VsZWN0ZWQtd3JhcHBlciB7XG4gICAgYmFja2dyb3VuZDogI2ZmZjtcbn1cblxuLm11bHRpLXdyYXBwZXIgLmhlYWRlciB7XG4gICAgY29sb3I6ICM0ZjRmNGY7XG4gICAgY3Vyc29yOiBkZWZhdWx0O1xuICAgIGZvbnQtd2VpZ2h0OiBib2xkO1xuICAgIG1hcmdpbi1ib3R0b206IDVweDtcbiAgICBwYWRkaW5nOiA1cHggMTBweDtcbn1cblxuLm11bHRpLXdyYXBwZXIgLml0ZW0ge1xuICAgIGN1cnNvcjogcG9pbnRlcjtcbiAgICBkaXNwbGF5OiBibG9jaztcbiAgICBwYWRkaW5nOiA1cHggMTBweDtcbn1cblxuLm11bHRpLXdyYXBwZXIgLml0ZW06aG92ZXIge1xuICAgIGJhY2tncm91bmQ6ICNlY2VjZWM7XG4gICAgYm9yZGVyLXJhZGl1czogMnB4O1xufVxuXG4ubXVsdGktd3JhcHBlciAuaXRlbS1ncm91cCB7XG4gICAgcGFkZGluZzogNXB4IDEwcHg7XG59XG5cbi5tdWx0aS13cmFwcGVyIC5pdGVtLWdyb3VwIC5ncm91cC1sYWJlbCB7XG4gICAgZGlzcGxheTogYmxvY2s7XG4gICAgZm9udC1zaXplOiAwLjg3NXJlbTtcbiAgICBvcGFjaXR5OiAwLjU7XG4gICAgcGFkZGluZzogNXB4IDA7XG59XG5cbi5tdWx0aS13cmFwcGVyIC5zZWFyY2gtaW5wdXQge1xuICAgIGJvcmRlcjogMDtcbiAgICBib3JkZXItYm90dG9tOiAxcHggc29saWQgI2NjYztcbiAgICBib3JkZXItcmFkaXVzOiAwO1xuICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgIGZvbnQtc2l6ZTogMWVtO1xuICAgIG1hcmdpbjogMDtcbiAgICBvdXRsaW5lOiAwO1xuICAgIHBhZGRpbmc6IDEwcHggMjBweDtcbiAgICB3aWR0aDogMTAwJTtcbiAgICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xufVxuXG4ubXVsdGktd3JhcHBlciAubm9uLXNlbGVjdGVkLXdyYXBwZXIgLml0ZW0uc2VsZWN0ZWQge1xuICAgIG9wYWNpdHk6IDAuNTtcbn1cblxuLm11bHRpLXdyYXBwZXIgLm5vbi1zZWxlY3RlZC13cmFwcGVyIC5pdGVtLmRpc2FibGVkLFxuLm11bHRpLXdyYXBwZXIgLnNlbGVjdGVkLXdyYXBwZXIgLml0ZW0uZGlzYWJsZWQge1xuICAgIG9wYWNpdHk6IDAuNTtcbiAgICB0ZXh0LWRlY29yYXRpb246IGxpbmUtdGhyb3VnaDtcbn1cblxuLm11bHRpLXdyYXBwZXIgLm5vbi1zZWxlY3RlZC13cmFwcGVyIC5pdGVtLmRpc2FibGVkOmhvdmVyLFxuLm11bHRpLXdyYXBwZXIgLnNlbGVjdGVkLXdyYXBwZXIgLml0ZW0uZGlzYWJsZWQ6aG92ZXIge1xuICAgIGJhY2tncm91bmQ6IGluaGVyaXQ7XG4gICAgY3Vyc29yOiBpbmhlcml0O1xufSIsIi5zZiB7XG5cbiAgJl9faW5saW5le1xuICAgIGRpc3BsYXk6IGlubGluZS1ibG9jaztcbiAgICBtYXJnaW4tcmlnaHQ6IDA7XG4gIH1cblxuICAmX190YWJsZSB7XG4gICAgdHI6Zmlyc3QtY2hpbGQgYnV0dG9ue1xuICAgICAgZGlzcGxheTogbm9uZTtcbiAgICB9XG4gICAgdGQge1xuICAgICAgcGFkZGluZy1sZWZ0OiAwO1xuICAgIH1cbiAgfVxuXG4gICZfX2xvZ28ge1xuICAgIG92ZXJmbG93OiBoaWRkZW47XG4gICAgdGV4dC1pbmRlbnQ6IC05OTk5OXB4O1xuICAgIGJhY2tncm91bmQ6IHVybChcIi4uL2ltYWdlcy9zZl9sb2dvLnN2Z1wiKSBuby1yZXBlYXQgY2VudGVyIGxlZnQ7XG4gICAgYmFja2dyb3VuZC1zaXplOiBjb250YWluO1xuICAgIG1heC13aWR0aDogMjk3cHg7XG4gICAgaGVpZ2h0OiA1M3B4O1xuICB9XG5cbiAgJl9fdmVyc2lvbiB7XG4gICAgY29sb3I6ICRncmF5O1xuICAgIGZvbnQtc2l6ZTogMTJweDtcbiAgICBsaW5lLWhlaWdodDogMTdweDtcbiAgICBtYXJnaW46IDVweCAwO1xuICB9XG5cbiAgJl9fYnV0dG9uLmJ1dHRvbiB7XG4gICAgY29sb3I6ICR3aGl0ZTtcbiAgICB0ZXh0LXRyYW5zZm9ybTogdXBwZXJjYXNlO1xuICAgIGJvcmRlci1jb2xvcjogJHNlY29uZGFyeTtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAkc2Vjb25kYXJ5O1xuICAgIEBpbmNsdWRlIGhvdmVyIHtcbiAgICAgIGNvbG9yOiAkd2hpdGU7XG4gICAgICBib3JkZXItY29sb3I6IGRhcmtlbigkc2Vjb25kYXJ5LCA1JSk7XG4gICAgICBiYWNrZ3JvdW5kLWNvbG9yOiBkYXJrZW4oJHNlY29uZGFyeSwgNSUpO1xuICAgIH1cbiAgfVxuXG4gICZfX2J1dHRvbl9fc2Vjb25kYXJ5LmJ1dHRvbixcbiAgJl9fYnV0dG9uX19sb2dvdXQuYnV0dG9uIHtcbiAgICBjb2xvcjogJHdoaXRlO1xuICAgIHRleHQtdHJhbnNmb3JtOiB1cHBlcmNhc2U7XG4gICAgYm9yZGVyLWNvbG9yOiAkcHJpbWFyeTtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiAkcHJpbWFyeTtcbiAgICBAaW5jbHVkZSBob3ZlciB7XG4gICAgICBjb2xvcjogJHdoaXRlO1xuICAgICAgYm9yZGVyLWNvbG9yOiBkYXJrZW4oJHByaW1hcnksIDUlKTtcbiAgICAgIGJhY2tncm91bmQtY29sb3I6IGRhcmtlbigkcHJpbWFyeSwgNSUpO1xuICAgIH1cbiAgfVxuXG4gICZfX3JlcXVpcmVtZW50cyB7XG4gICAgLnN1Y2Nlc3MsXG4gICAgLmZhaWxlZCB7XG4gICAgICBAaW5jbHVkZSBzbW9vdGhUZXh0O1xuICAgICAgcG9zaXRpb246IHJlbGF0aXZlO1xuICAgICAgcGFkZGluZy1sZWZ0OiAyNnB4O1xuICAgICAgY29sb3I6ICR0ZXh0Y29sb3I7XG5cbiAgICAgICY6YmVmb3JlIHtcbiAgICAgICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgICAgICB0b3A6IDA7XG4gICAgICAgIGxlZnQ6IDA7XG4gICAgICAgIGZvbnQtZmFtaWx5OiBkYXNoaWNvbnM7XG4gICAgICAgIGNvbnRlbnQ6IFwiXFxmMTQ3XCI7XG4gICAgICAgIGRpc3BsYXk6IGJsb2NrO1xuICAgICAgICB3aWR0aDogMTZweDtcbiAgICAgICAgaGVpZ2h0OiAxNnB4O1xuICAgICAgICBsaW5lLWhlaWdodDogMTZweDtcbiAgICAgICAgZm9udC1zaXplOiAxNHB4O1xuICAgICAgICBib3JkZXItcmFkaXVzOiA1MCU7XG4gICAgICAgIHRleHQtYWxpZ246IGNlbnRlcjtcbiAgICAgICAgY29sb3I6ICR3aGl0ZTtcbiAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogJHNlY29uZGFyeTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAuZmFpbGVkIHtcbiAgICAgIGNvbG9yOiAkdGV4dGNvbG9yO1xuXG4gICAgICAmOmJlZm9yZSB7XG4gICAgICAgIGNvbnRlbnQ6IFwiXFxmMzM1XCI7XG4gICAgICAgIGJhY2tncm91bmQtY29sb3I6ICRncmF5O1xuICAgICAgfVxuICAgIH1cblxuICB9XG5cbiAgJl9faGVybyB7XG4gICAgcG9zaXRpb246IHJlbGF0aXZlO1xuICAgIGJvcmRlcjogMDtcbiAgICBib3JkZXItcmFkaXVzOiAycHg7XG4gICAgYmFja2dyb3VuZDogbGluZWFyLWdyYWRpZW50KDE4MGRlZywgIzAzMjc0RCAwJSwgIzUyMzA4MSAxMDAlKTtcbiAgICBiYWNrZ3JvdW5kLXNpemU6IGNvdmVyO1xuICAgIHBhZGRpbmc6IDMwcHg7XG5cbiAgICAmOmJlZm9yZSB7XG4gICAgICBjb250ZW50OiBcIlwiO1xuICAgICAgZGlzcGxheTogYmxvY2s7XG4gICAgICB6LWluZGV4OiAxO1xuICAgICAgcG9zaXRpb246IGFic29sdXRlO1xuICAgICAgdG9wOiAwO1xuICAgICAgcmlnaHQ6IDMwcHg7XG4gICAgICBib3R0b206IDA7XG4gICAgICBsZWZ0OiAwO1xuICAgICAgYmFja2dyb3VuZDogdXJsKFwiLi4vaW1hZ2VzL3NmX21hcmtldGluZy5zdmdcIikgbm8tcmVwZWF0IGNlbnRlciByaWdodDtcbiAgICAgIHBvaW50ZXItZXZlbnRzOiBub25lO1xuICAgIH1cbiAgICAmLS10aXRsZXtcbiAgICAgIGZvbnQtc2l6ZTogMTZweDtcbiAgICAgIGxpbmUtaGVpZ2h0OiAyMnB4O1xuICAgICAgcGFkZGluZy1yaWdodDogMzBweDtcbiAgICAgIGNvbG9yOiAkd2hpdGU7XG4gICAgICBmb250LXdlaWdodDogYm9sZDtcbiAgICAgIG1hcmdpbi1ib3R0b206IDE1cHg7XG4gICAgfVxuICB9XG5cbiAgJl9fbWFya2V0aW5nIHtcbiAgICBib3JkZXItbGVmdDogMXB4IHNvbGlkICRwcmltYXJ5O1xuICAgIHBhZGRpbmctbGVmdDogMjZweDtcblxuICAgICYtLXRpdGxle1xuICAgICAgY29sb3I6ICRwcmltYXJ5O1xuICAgICAgZm9udC1zaXplOiAxLjVlbTtcbiAgICAgIG1hcmdpbjogMDtcbiAgICAgIG1hcmdpbi10b3A6IDFlbTtcbiAgICB9XG4gICAgJi0tc3VidGl0bGV7XG4gICAgICBjb2xvcjogJGdyYXk7XG4gICAgICBmb250LXNpemU6IDEwcHg7XG4gICAgICB0ZXh0LXRyYW5zZm9ybTogdXBwZXJjYXNlO1xuICAgICAgbGV0dGVyLXNwYWNpbmc6IDMuMzNweDtcbiAgICAgIG1hcmdpbjogMDtcbiAgICAgIHBhZGRpbmctdG9wOiA1cHg7XG4gICAgfVxuICAgICYtLXRleHR7XG4gICAgICBjb2xvcjogJHRleHRjb2xvcjtcbiAgICAgIGZvbnQtc2l6ZTogMTJweDtcbiAgICAgIGxldHRlci1zcGFjaW5nOiAwO1xuICAgICAgbGluZS1oZWlnaHQ6IDE3cHg7XG4gICAgfVxuXG4gICAgJi0tZG93bmxvYWQge1xuICAgICAgcGFkZGluZzogMWVtIDA7XG5cbiAgICAgIGxpIHtcbiAgICAgICAgbGluZS1oZWlnaHQ6IDEuNWVtO1xuICAgICAgfVxuXG4gICAgICBhIHtcbiAgICAgICAgQGluY2x1ZGUgc21vb3RoVGV4dDtcbiAgICAgICAgcG9zaXRpb246IHJlbGF0aXZlO1xuICAgICAgICBwYWRkaW5nLWxlZnQ6IDI2cHg7XG4gICAgICAgIGNvbG9yOiAkYmx1ZTtcbiAgICAgICAgZm9udC13ZWlnaHQ6IGJvbGQ7XG5cbiAgICAgICAgJjpiZWZvcmUge1xuICAgICAgICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICAgICAgICB0b3A6IDA7XG4gICAgICAgICAgbGVmdDogMDtcbiAgICAgICAgICBmb250LWZhbWlseTogZGFzaGljb25zO1xuICAgICAgICAgIGNvbnRlbnQ6IFwiXFxmMzQ2XCI7XG4gICAgICAgICAgZGlzcGxheTogYmxvY2s7XG4gICAgICAgICAgd2lkdGg6IDE2cHg7XG4gICAgICAgICAgaGVpZ2h0OiAxNnB4O1xuICAgICAgICAgIGxpbmUtaGVpZ2h0OiAxNnB4O1xuICAgICAgICAgIGZvbnQtc2l6ZTogMTRweDtcbiAgICAgICAgICBib3JkZXItcmFkaXVzOiA1MCU7XG4gICAgICAgICAgdGV4dC1hbGlnbjogY2VudGVyO1xuICAgICAgICAgIGNvbG9yOiAkd2hpdGU7XG4gICAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogJHByaW1hcnk7XG4gICAgICAgIH1cblxuICAgICAgICAmOmhvdmVyIHtcbiAgICAgICAgICBjb2xvcjogJHByaW1hcnk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAmX19wbHVnaW57XG4gICAgLnNmX19ub3RpY2UtLXN0YXJ0IGF7XG4gICAgICBkaXNwbGF5OiBub25lO1xuICAgIH1cbiAgfVxuXG5cbiAgQGluY2x1ZGUgYnJlYWtwb2ludHMobWQpIHtcbiAgICAmX19jb2x1bW5zIHtcbiAgICAgIGRpc3BsYXk6IGZsZXg7XG4gICAgICBmbGV4LXdyYXA6IHdyYXA7XG4gICAgfVxuICAgICZfX2NvbHVtbiB7XG4gICAgICBmbGV4LWJhc2lzOiA2NiU7XG5cbiAgICAgICY6bGFzdC1jaGlsZCB7XG4gICAgICAgIGZsZXgtYmFzaXM6IDMzJTtcbiAgICAgIH1cbiAgICB9XG5cbiAgfVxufVxuIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBR0FBLEFBQUEsY0FBYyxDQUFDO0VBQ1gsTUFBTSxFQUFFLGNBQWM7RUFDdEIsYUFBYSxFQUFFLEdBQUc7RUFDbEIsS0FBSyxFQUFFLElBQUksR0FDZDs7QUFF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 */ -
shopping-feed/trunk/assets/scss/main/_sf.scss
r2339808 r2670662 1 1 .sf { 2 3 &__inline{ 4 display: inline-block; 5 margin-right: 0; 6 } 7 8 &__table { 9 tr:first-child button{ 10 display: none; 11 } 12 td { 13 padding-left: 0; 14 } 15 } 2 16 3 17 &__logo { … … 29 43 } 30 44 45 &__button__secondary.button, 31 46 &__button__logout.button { 32 47 color: $white; -
shopping-feed/trunk/readme.txt
r2613147 r2670662 2 2 Contributors: ShoppingFeed, BeAPI 3 3 Tags: shoppingfeed, marketplace, woocommerce, woocommerce shoppingfeed, create woocommerce products shoppingfeed, products feed, generate shoppingfeed, amazon, Jet, Walmart, many marketplace, import orders 4 Stable tag: 6. 0.335 Version: 6. 0.334 Stable tag: 6.1.0 5 Version: 6.1.0 6 6 Requires PHP: 5.6 7 7 Requires at least: 5.2 … … 46 46 6.0.31 Do not send mails to other customers 47 47 6.0.32 Add link to WC logs 48 6. 0.33 Fix priority issue with other plugins48 6.1.0 Add the possibility to connect multiple ShoppingFeed accounts to one WC shop 49 49 50 50 == Description == -
shopping-feed/trunk/shoppingfeed.php
r2613147 r2670662 8 8 * Text Domain: shopping-feed 9 9 * Domain Path: /languages 10 * Version: 6. 0.3310 * Version: 6.1.0 11 11 * Requires at least WP: 5.7 12 12 * Requires at least WooCommerce: 5.1.0 … … 26 26 } 27 27 28 define( 'SF_VERSION', '6.0.33' ); 28 define( 'SF_VERSION', '6.1.0' ); 29 define( 'SF_DB_VERSION_SLUG', 'SF_DB_VERSION' ); 30 define( 'SF_DB_VERSION', '1.0.0' ); 31 define( 'SF_UPGRADE_RUNNING', 'SF_UPGRADE_RUNNING' ); 29 32 define( 'SF_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); 30 33 define( 'SF_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); … … 53 56 } 54 57 55 \add_action( 'plugins_loaded', __NAMESPACE__ . '\\init', 100);58 \add_action( 'plugins_loaded', __NAMESPACE__ . '\\init', 99 ); -
shopping-feed/trunk/src/Actions/Actions.php
r2339808 r2670662 37 37 */ 38 38 public static function register_get_orders() { 39 as_schedule_recurring_action( 40 time() + 60, 41 ShoppingFeedHelper::get_sf_orders_import_frequency(), 42 'sf_get_orders_action', 43 array(), 44 self::ORDERS_GROUP 45 ); 39 $sf_accounts = ShoppingFeedHelper::get_sf_account_options(); 40 if ( empty( $sf_accounts ) ) { 41 ShoppingFeedHelper::get_logger()->error( 42 sprintf( 43 __( 'No Accounts founds', 'shopping-feed' ) 44 ), 45 array( 46 'source' => 'shopping-feed', 47 ) 48 ); 49 50 return; 51 } 52 foreach ( $sf_accounts as $key => $sf_account ) { 53 as_schedule_recurring_action( 54 time() + 60, 55 ShoppingFeedHelper::get_sf_orders_import_frequency(), 56 'sf_get_orders_action_' . $key, 57 array( 58 'sf_account' => $sf_account, 59 ), 60 self::ORDERS_GROUP 61 ); 62 } 46 63 } 47 64 -
shopping-feed/trunk/src/Admin/Metabox.php
r2339808 r2670662 64 64 } 65 65 66 $reference = $order->get_meta( Query:: $wc_meta_sf_reference);67 $channel_name = $order->get_meta( Query:: $wc_meta_sf_channel_name);66 $reference = $order->get_meta( Query::WC_META_SF_REFERENCE ); 67 $channel_name = $order->get_meta( Query::WC_META_SF_CHANNEL_NAME ); 68 68 69 69 if ( empty( $reference ) && empty( $channel_name ) ) : ?> -
shopping-feed/trunk/src/Admin/Notices.php
r2339808 r2670662 20 20 21 21 public function admin_notices() { 22 $options = ShoppingFeedHelper::get_sf_account_options(); 23 if ( 24 empty( $options['token'] ) && 25 get_current_screen()->parent_base !== Options::SF_SLUG ) { 26 if ( empty( $options['username'] ) || empty( $options['password'] ) ) { 27 $this->display_notice(); 28 } 29 } 22 //TODO: CHECK ALL CREDENTIALS 23 return; 24 // $options = ShoppingFeedHelper::get_sf_account_options(); 25 // if ( 26 // empty( $options['token'] ) && 27 // get_current_screen()->parent_base !== Options::SF_SLUG ) { 28 // if ( empty( $options['username'] ) || empty( $options['password'] ) ) { 29 // $this->display_notice(); 30 // } 31 // } 30 32 } 31 33 -
shopping-feed/trunk/src/Admin/Options.php
r2602861 r2670662 58 58 /** @var array $sf_orders_options */ 59 59 private $sf_orders_options; 60 /** @var bool $connected */ 61 private $connected = true; 60 62 61 63 62 /** … … 114 113 ); 115 114 115 /** 116 * Clean and register new cron once account option updated 117 */ 116 118 add_action( 117 'admin_action_ sf_logout',118 function () { 119 delete_option( Options::SF_ACCOUNT_OPTIONS);120 wp_safe_redirect( ShoppingFeedHelper::get_setting_link(), 302);119 'admin_action_update', 120 function () { 121 Actions::clean_get_orders(); 122 Actions::register_get_orders(); 121 123 } 122 124 ); … … 225 227 */ 226 228 public function init_account_setting_page() { 227 $this->connected = ShoppingFeedHelper::is_authenticated();228 229 229 //check clean action 230 230 $this->check_clean_action(); … … 240 240 self::SF_ACCOUNT_SETTINGS_PAGE 241 241 ); 242 243 add_settings_field(244 'username',245 __( 'Username', 'shopping-feed' ),246 function () {247 printf(248 '<input class="regular-text" type="text" name="sf_account_options[username]" id="username" value="%s">',249 isset( $this->sf_account_options['username'] ) ? esc_attr( $this->sf_account_options['username'] ) : ''250 );251 },252 self::SF_ACCOUNT_SETTINGS_PAGE,253 'sf_account_settings'254 );255 256 add_settings_field(257 'password',258 __( 'Password', 'shopping-feed' ),259 function () {260 printf(261 '<input class="regular-text" type="password" name="sf_account_options[password]" id="password" value="%s">',262 isset( $this->sf_account_options['password'] ) ? esc_attr( $this->sf_account_options['password'] ) : ''263 );264 },265 self::SF_ACCOUNT_SETTINGS_PAGE,266 'sf_account_settings'267 );268 269 if ( $this->connected ) {270 add_settings_field(271 'url',272 __( 'Your source feed', 'shopping-feed' ),273 function () {274 $sf_feed_public_url = ShoppingFeedHelper::get_public_feed_url();275 $sf_process_running = ShoppingFeedHelper::generation_process_running();276 $sf_last_generation_date = get_option( Generator::SF_FEED_LAST_GENERATION_DATE );277 ?>278 <?php if ( ! $sf_process_running ) : ?>279 <a href="<?php echo esc_html( $sf_feed_public_url ); ?>" target="_blank">280 <?php281 echo esc_url( $sf_feed_public_url );282 ;283 ?>284 </a>285 <?php endif; ?>286 <br>287 <p>288 <?php if ( ! $sf_process_running ) : ?>289 <?php esc_html_e( 'Last update', 'shopping-feed' ); ?> :290 <?php291 ! empty( $sf_last_generation_date ) ? esc_html( $sf_last_generation_date ) : esc_html_e( 'Never', 'shopping-feed' );292 ?>293 <a href="<?php echo esc_url( ShoppingFeedHelper::get_public_feed_url_with_generation() ); ?>" target="_blank">294 <?php esc_html_e( 'Refresh', 'shopping-feed' ); ?>295 </a>296 <?php else : ?>297 <strong>(<?php esc_html_e( 'The feed is update is running', 'shopping-feed' ); ?>) <a href="#" onClick="window.location.reload();"><?php esc_html_e( 'Refresh to check progress', 'shopping-feed' ); ?></a></strong>298 <?php endif; ?>299 </p>300 <?php301 },302 self::SF_ACCOUNT_SETTINGS_PAGE,303 'sf_account_settings'304 );305 }306 307 add_settings_field(308 'status',309 __( 'Status', 'shopping-feed' ),310 function () {311 ?>312 <div class="notice-<?php echo esc_html( $this->connected ? 'success' : 'error' ); ?> regular-text notice-alt">313 <?php314 echo esc_html( $this->connected ? _e( 'Connected', 'shopping-feed' ) : _e( 'Not connected', 'shopping-feed' ) );315 ?>316 </div>317 <?php318 },319 self::SF_ACCOUNT_SETTINGS_PAGE,320 'sf_account_settings'321 );322 242 ?> 323 243 <div class="wrap"> 324 244 <?php settings_errors(); ?> 325 245 326 <div class="sf__columns"> 327 <div class="sf__column"> 328 <form method="post" action="options.php"> 329 <?php 330 settings_fields( 'sf_account_page_fields' ); 331 do_settings_sections( self::SF_ACCOUNT_SETTINGS_PAGE ); 332 if ( ! $this->connected ) { 333 submit_button( __( 'Login', 'shopping-feed' ), 'sf__button' ); 334 } else { 335 echo '<input class="hidden" name="action" value="sf_logout">'; 336 submit_button( __( 'Logout', 'shopping-feed' ), 'sf__button__logout', 'logout' ); 337 } 338 ?> 339 </form> 340 <div class="sf__requirements"> 341 <?php 342 $requirements = Requirements::get_instance(); 343 echo wp_kses_post( $requirements->curl_requirement() ); 344 echo wp_kses_post( $requirements->php_requirement() ); 345 echo wp_kses_post( $requirements->openssl_requirement() ); 346 echo wp_kses_post( $requirements->account_requirement() ); 347 echo wp_kses_post( $requirements->uploads_directory_access_requirement() ); 348 ?> 246 <div class="sf__columns"> 247 <div class="sf__column account__wrapper"> 248 <form method="post" action="options.php"> 249 <div class="blocks"> 250 <div class="block_links"> 251 <table class="form-table sf__table"> 252 <thead> 253 <tr> 254 <th> <?php esc_html_e( 'Username', 'shopping-feed' ); ?> </th> 255 <th> <?php esc_html_e( 'Password', 'shopping-feed' ); ?> </th> 256 <th></th> 257 </tr> 258 </thead> 259 <tbody> 260 <tr> 261 <td><input class="regular-text user" type="text" 262 name="sf_account_options[0][username]" 263 value="<?php echo isset( $this->sf_account_options[0]['username'] ) ? esc_attr( $this->sf_account_options[0]['username'] ) : ''; ?>"> 264 </td> 265 <td><input class="regular-text pass" type="password" 266 name="sf_account_options[0][password]" 267 value="<?php echo isset( $this->sf_account_options[0]['password'] ) ? esc_attr( $this->sf_account_options[0]['password'] ) : ''; ?>"> 268 </td> 269 <td> 270 <button class="button sf__button__secondary delete_link sf__button--delete"> 271 Delete 272 </button> 273 </td> 274 <td class="hidden"><input name="sf_account_options[0][token]" 275 value="<?php echo isset( $this->sf_account_options[0]['token'] ) ? esc_attr( $this->sf_account_options[0]['token'] ) : ''; ?>"> 276 </td> 277 <td class="hidden"><input name="sf_account_options[0][sf_store_id]" 278 value="<?php echo isset( $this->sf_account_options[0]['sf_store_id'] ) ? esc_attr( $this->sf_account_options[0]['sf_store_id'] ) : ''; ?>"> 279 </td> 280 </tr> 281 <?php 282 if ( count( $this->sf_account_options ) > 1 ) { 283 foreach ( $this->sf_account_options as $key => $sf_account_option ) { 284 if ( 0 === $key ) { 285 continue; 286 } 287 ?> 288 <tr> 289 <td><input class="regular-text user" type="text" 290 name="sf_account_options[<?php echo esc_attr( $key ); ?>][username]" 291 value="<?php echo isset( $this->sf_account_options[ $key ]['username'] ) ? esc_attr( $this->sf_account_options[ $key ]['username'] ) : ''; ?>"> 292 </td> 293 <td><input class="regular-text pass" type="password" 294 name="sf_account_options[<?php echo esc_attr( $key ); ?>][password]" 295 value="<?php echo isset( $this->sf_account_options[ $key ]['password'] ) ? esc_attr( $this->sf_account_options[ $key ]['password'] ) : ''; ?>"> 296 </td> 297 <td class="hidden"><input 298 name="sf_account_options[<?php echo esc_attr( $key ); ?>][token]" 299 value="<?php echo isset( $this->sf_account_options[ $key ]['token'] ) ? esc_attr( $this->sf_account_options[ $key ]['token'] ) : ''; ?>"> 300 </td> 301 <td class="hidden"><input 302 name="sf_account_options[<?php echo esc_attr( $key ); ?>][sf_store_id]" 303 value="<?php echo isset( $this->sf_account_options[ $key ]['sf_store_id'] ) ? esc_attr( $this->sf_account_options[ $key ]['sf_store_id'] ) : ''; ?>"> 304 </td> 305 <td> 306 <button class="button sf__button__secondary delete_link sf__button--delete"> 307 Delete 308 </button> 309 </td> 310 </tr> 311 <?php 312 } 313 } 314 ?> 315 </tbody> 316 </table> 317 <div class="sf__inline"> 318 <p> 319 <button class="button sf__button__secondary add_link"><?php esc_html_e( 'Add account', 'shopping-feed' ); ?></button> 320 </p> 321 </div> 322 <div class="sf__inline"> 323 <?php 324 settings_fields( 'sf_account_page_fields' ); 325 submit_button( __( 'Save', 'shopping-feed' ), 'sf__button' ); 326 ?> 327 </div> 328 </form> 329 </div> 330 </div> 331 <!-- Line template --> 332 <script type="text/html" id="tpl-line"> 333 <tr> 334 <td><input class="regular-text user" type="text" name="sf_account_options[<%= row %>][username]" 335 value="<%= user %>"></td> 336 <td><input class="regular-text pass" type="password" name="sf_account_options[<%= row %>][password]" 337 value="<%= pass %>"></td> 338 <td> 339 <button class="button sf__button__secondary sf__button--delete delete_link">Delete</button> 340 </td> 341 </tr> 342 </script> 343 <div class="sf__requirements"> 344 <?php 345 $requirements = Requirements::get_instance(); 346 echo wp_kses_post( $requirements->curl_requirement() ); 347 echo wp_kses_post( $requirements->php_requirement() ); 348 echo wp_kses_post( $requirements->openssl_requirement() ); 349 echo wp_kses_post( $requirements->uploads_directory_access_requirement() ); 350 ?> 349 351 <!-- REQUIREMENTS --> 350 352 </div> … … 365 367 private function check_clean_action() { 366 368 if ( ! empty( $_GET['clean_process'] ) ) { 367 ShoppingFeedHelper::clean_ generation_process_running();369 ShoppingFeedHelper::clean_process_running( 'sf_feed_generation_process' ); 368 370 } 369 371 } … … 385 387 ); 386 388 389 wp_enqueue_script( 390 'accounts', 391 SF_PLUGIN_URL . 'assets/js/accounts.js', 392 array( 'jquery', 'underscore' ), 393 true, 394 true 395 ); 396 387 397 wp_enqueue_script( 'multi_js_init', SF_PLUGIN_URL . 'assets/js/init.js', array( 'multi_js' ), true ); 388 398 wp_localize_script( … … 390 400 'sf_options', 391 401 array( 392 'selected_orders' => __( 'Selected order status', 'shopping-feed' ),402 'selected_orders' => __( 'Selected order status', 'shopping-feed' ), 393 403 'unselected_orders' => __( 'Unselected order status', 'shopping-feed' ), 394 'search' => __( 'Search', 'shopping-feed' ),404 'search' => __( 'Search', 'shopping-feed' ), 395 405 ) 396 406 ); … … 401 411 */ 402 412 private function init_feed_setting_page() { 403 $this->check_connection();404 413 405 414 //load assets … … 413 422 }, 414 423 self::SF_FEED_SETTINGS_PAGE 424 ); 425 426 add_settings_field( 427 'url', 428 __( 'Your source feed', 'shopping-feed' ), 429 function () { 430 $sf_feed_public_url = ShoppingFeedHelper::get_public_feed_url(); 431 $sf_process_running = ShoppingFeedHelper::is_process_running( 'sf_feed_generation_process' ); 432 $sf_last_generation_date = get_option( Generator::SF_FEED_LAST_GENERATION_DATE ); 433 ?> 434 <?php if ( ! $sf_process_running ) : ?> 435 <a href="<?php echo esc_html( $sf_feed_public_url ); ?>" target="_blank"> 436 <?php 437 echo esc_url( $sf_feed_public_url ); 438 ; 439 ?> 440 </a> 441 <?php endif; ?> 442 <br> 443 <p> 444 <?php if ( ! $sf_process_running ) : ?> 445 <?php esc_html_e( 'Last update', 'shopping-feed' ); ?> : 446 <?php 447 echo ! empty( $sf_last_generation_date ) ? esc_html( $sf_last_generation_date ) : esc_html__( 'Never', 'shopping-feed' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 448 ?> 449 <a href="<?php echo esc_url( ShoppingFeedHelper::get_public_feed_url_with_generation() ); ?>" target="_blank"> 450 <?php esc_html_e( 'Refresh', 'shopping-feed' ); ?> 451 </a> 452 <?php else : ?> 453 <strong>(<?php esc_html_e( 'The feed is update is running', 'shopping-feed' ); ?>) <a href="#" onClick="window.location.reload();"><?php esc_html_e( 'Refresh to check progress', 'shopping-feed' ); ?></a></strong> 454 <?php endif; ?> 455 </p> 456 <?php 457 }, 458 self::SF_FEED_SETTINGS_PAGE, 459 'sf_feed_settings_categories' 415 460 ); 416 461 … … 554 599 __( 'Batch size', 'shopping-feed' ), 555 600 function () { 556 $running_process = ShoppingFeedHelper::get_running_ generation_feed_process();601 $running_process = ShoppingFeedHelper::get_running_process( 'sf_feed_generation_process' ); 557 602 $running_process = is_array( $running_process ) ? count( $running_process ) : 0; 558 603 ?> … … 657 702 658 703 /** 659 * Check connection with SF platform with correct credentials660 * If not redirect to Account page661 */662 private function check_connection() {663 if ( ! ShoppingFeedHelper::is_authenticated() ) {664 wp_safe_redirect( sprintf( '%s&no_connected=%s', ShoppingFeedHelper::get_setting_link(), 'true' ) );665 }666 }667 668 /**669 704 * Define Shipping Page 670 705 */ 671 706 private function init_shipping_setting_page() { 672 $this->check_connection();673 674 707 //load assets 675 708 $this->load_assets(); … … 826 859 827 860 private function init_orders_setting_page() { 828 $this->check_connection();829 830 861 //load assets 831 862 $this->load_assets(); -
shopping-feed/trunk/src/Admin/Requirements.php
r2542211 r2670662 83 83 * @return string 84 84 */ 85 public function account_requirement() {86 return ( $this->valid_account() )87 ? '<p class="success">' . __( 'You are logged in your ShoppingFeed account.', 'shopping-feed' ) . '</p>'88 : '<p class="failed">' . __( 'You must be logged in your ShoppingFeed account.', 'shopping-feed' ) . '</p>';89 }90 91 92 /**93 * @return string94 */95 85 public function uploads_directory_access_requirement() { 96 86 return ( $this->uploads_directory_writable() ) … … 137 127 138 128 /** 139 * Check if the user is logged in.140 *141 * @return bool142 */143 public function valid_account() {144 return ShoppingFeedHelper::is_authenticated();145 }146 147 /**148 129 * Check if the uploads directory is writable 149 130 * -
shopping-feed/trunk/src/Admin/WoocommerceActions.php
r2542211 r2670662 10 10 use ShoppingFeed\Sdk\Api\Catalog\PricingUpdate; 11 11 use ShoppingFeed\Sdk\Api\Store\StoreResource; 12 use ShoppingFeed\Sdk\Client; 13 use ShoppingFeed\Sdk\Credential; 12 14 use ShoppingFeed\ShoppingFeedWC\Feed\AsyncGenerator; 13 15 use ShoppingFeed\ShoppingFeedWC\Feed\Generator; … … 16 18 use ShoppingFeed\ShoppingFeedWC\Orders\Orders; 17 19 use ShoppingFeed\ShoppingFeedWC\Products\Product; 20 use ShoppingFeed\ShoppingFeedWC\Query\Query; 18 21 use ShoppingFeed\ShoppingFeedWC\Sdk\Sdk; 19 22 use ShoppingFeed\ShoppingFeedWC\ShoppingFeedHelper; 20 21 23 22 24 /** … … 63 65 add_action( 64 66 'sf_feed_generation_combine_feed_parts', 65 [67 array( 66 68 AsyncGenerator::get_instance(), 67 69 'combine_feed_parts', 68 ]70 ) 69 71 ); 70 72 … … 84 86 85 87 //Get Orders 86 add_action( 87 'sf_get_orders_action', 88 function () { 89 Orders::get_instance()->get_orders(); 90 } 91 ); 88 $sf_accounts = ShoppingFeedHelper::get_sf_account_options(); 89 if ( empty( $sf_accounts ) ) { 90 ShoppingFeedHelper::get_logger()->error( 91 sprintf( 92 __( 'No Accounts founds', 'shopping-feed' ) 93 ), 94 array( 95 'source' => 'shopping-feed', 96 ) 97 ); 98 } else { 99 foreach ( $sf_accounts as $key => $sf_account ) { 100 add_action( 101 'sf_get_orders_action_' . $key, 102 function ( $sf_account ) { 103 Orders::get_instance()->get_orders( $sf_account ); 104 } 105 ); 106 } 107 } 92 108 93 109 //Acknowledge Remain Order … … 102 118 103 119 /** 120 * Migrate old accounts to multi account format 121 */ 122 add_action( 'sf_migrate_single_action', array( $this, 'migrate_old_accounts' ) ); 123 124 /** 104 125 * Orders Statuses Mapping 105 126 * Each status with action … … 107 128 */ 108 129 $statuses_actions = ShoppingFeedHelper::get_sf_statuses_actions(); 109 if ( 0 < $statuses_actions ) { 110 foreach ( $statuses_actions as $sf_action => $wc_statuses ) { 111 if ( ! is_array( $wc_statuses ) || '' === $sf_action ) { 112 continue; 113 } 114 115 foreach ( $wc_statuses as $wc_status ) { 116 $status = str_replace( 'wc-', '', $wc_status ); 117 $action = 'woocommerce_order_status_' . $status; 118 add_action( 119 $action, 120 function ( $order_id ) use ( $sf_action ) { 121 //if its not a sf order 122 if ( ! Order::is_sf_order( $order_id ) ) { 123 return; 124 } 125 try { 126 $operations = new Operations( $order_id ); 127 if ( ! method_exists( $operations, $sf_action ) ) { 128 ShoppingFeedHelper::get_logger()->error( 129 sprintf( 130 /* translators: %s: Action name. */ 131 __( 'Cant find any matched method for %s', 'shopping-feed' ), 132 $sf_action 133 ), 134 array( 135 'source' => 'shopping-feed', 136 ) 137 ); 138 139 return; 140 } 141 call_user_func( array( $operations, $sf_action ) ); 142 } catch ( Exception $exception ) { 143 wc_get_order( $order_id )->add_order_note( 144 sprintf( 145 /* translators: %s: Action */ 146 __( 'Failed to %s order', 'shopping-feed' ), 147 ucfirst( $sf_action ) 148 ) 149 ); 130 if ( empty( $statuses_actions ) ) { 131 return; 132 } 133 foreach ( $statuses_actions as $sf_action => $wc_statuses ) { 134 if ( ! is_array( $wc_statuses ) || '' === $sf_action ) { 135 continue; 136 } 137 138 foreach ( $wc_statuses as $wc_status ) { 139 $status = str_replace( 'wc-', '', $wc_status ); 140 $action = 'woocommerce_order_status_' . $status; 141 add_action( 142 $action, 143 function ( $order_id ) use ( $sf_action ) { 144 //if its not a sf order 145 if ( ! Order::is_sf_order( $order_id ) ) { 146 return; 147 } 148 try { 149 $operations = new Operations( $order_id ); 150 if ( ! method_exists( $operations, $sf_action ) ) { 150 151 ShoppingFeedHelper::get_logger()->error( 151 152 sprintf( 152 /* translators: %1$s: Action. %2$s: Error Message */ 153 __( 'Failed to %1$s order => %2$s', 'shopping-feed' ), 154 ucfirst( $sf_action ), 155 $exception->getMessage() 153 /* translators: %s: Action name. */ 154 __( 'Cant find any matched method for %s', 'shopping-feed' ), 155 $sf_action 156 156 ), 157 157 array( … … 159 159 ) 160 160 ); 161 162 return; 161 163 } 164 call_user_func( array( $operations, $sf_action ) ); 165 } catch ( Exception $exception ) { 166 wc_get_order( $order_id )->add_order_note( 167 sprintf( 168 /* translators: %s: Action */ 169 __( 'Failed to %s order', 'shopping-feed' ), 170 ucfirst( $sf_action ) 171 ) 172 ); 173 ShoppingFeedHelper::get_logger()->error( 174 sprintf( 175 /* translators: %1$s: Action. %2$s: Error Message */ 176 __( 'Failed to %1$s order => %2$s', 'shopping-feed' ), 177 ucfirst( $sf_action ), 178 $exception->getMessage() 179 ), 180 array( 181 'source' => 'shopping-feed', 182 ) 183 ); 162 184 } 163 );164 }185 } 186 ); 165 187 } 166 188 } … … 182 204 * @param $product_id 183 205 * @param bool $only_stock 184 *185 * @return bool186 206 */ 187 207 public function update_product( $product_id, $only_stock = false ) { 188 $sdk = Sdk::get_instance(); 189 if ( ! $sdk->get_default_shop() instanceof StoreResource ) { 190 ShoppingFeedHelper::get_logger()->error( __( 'Can\'t find default shop', 'shopping-feed' ) ); 191 192 return false; 193 } 194 195 /** @var StoreResource $shop */ 196 $shop = $sdk->get_default_shop(); 197 $pricing_api = $shop->getPricingApi(); 198 $inventory_api = $shop->getInventoryApi(); 199 200 $this->pricing_update = new \ShoppingFeed\Sdk\Api\Catalog\PricingUpdate(); 201 $this->inventory_update = new \ShoppingFeed\Sdk\Api\Catalog\InventoryUpdate(); 202 203 $product = new Product( $product_id ); 204 if ( $product->has_variations() ) { 205 foreach ( $product->get_variations() as $variation ) { 206 if ( empty( $variation['sku'] ) ) { 207 ShoppingFeedHelper::get_logger()->warning( 208 sprintf( 209 /* translators: %s: Product ID. */ 210 __( 'Cant update product without SKU => %s', 'shopping-feed' ), 211 $product_id 212 ), 213 array( 214 'source' => 'shopping-feed', 215 ) 216 ); 217 218 continue; 219 } 220 221 $this->may_update_pricing( $variation['sku'], ! empty( $variation['discount'] ) ? $variation['discount'] : $variation['price'] ); 222 $this->may_update_inventory( $variation['sku'], $variation['quantity'] ); 223 } 224 } else { 225 if ( empty( $product->get_sku() ) ) { 226 ShoppingFeedHelper::get_logger()->warning( 208 $sf_accounts = ShoppingFeedHelper::get_sf_account_options(); 209 if ( empty( $sf_accounts ) ) { 210 ShoppingFeedHelper::get_logger()->error( 211 sprintf( 212 __( 'No Accounts founds', 'shopping-feed' ) 213 ), 214 array( 215 'source' => 'shopping-feed', 216 ) 217 ); 218 219 return; 220 } 221 222 foreach ( $sf_accounts as $sf_account ) { 223 $shop = Sdk::get_sf_shop( $sf_account ); 224 if ( ! $shop instanceof StoreResource ) { 225 ShoppingFeedHelper::get_logger()->error( 227 226 sprintf( 228 /* translators: %s: Product ID. */229 __( 'Can t update product without SKU =>%s', 'shopping-feed' ),230 $ product_id227 /* translators: %s: Error message. */ 228 __( 'Cannot retrieve shop from SDK for account : %s', 'shopping-feed' ), 229 $sf_account['username'] 231 230 ), 232 231 array( … … 234 233 ) 235 234 ); 235 continue; 236 } 237 238 $pricing_api = $shop->getPricingApi(); 239 $inventory_api = $shop->getInventoryApi(); 240 241 $this->pricing_update = new \ShoppingFeed\Sdk\Api\Catalog\PricingUpdate(); 242 $this->inventory_update = new \ShoppingFeed\Sdk\Api\Catalog\InventoryUpdate(); 243 244 $product = new Product( $product_id ); 245 if ( $product->has_variations() ) { 246 if ( ! $this->update_variation_product( $product ) ) { 247 continue; 248 } 249 } else { 250 if ( ! $this->update_normal_product( $product ) ) { 251 continue; 252 } 253 } 254 /** 255 * Check if we need to update the price or only the stock 256 */ 257 if ( ! $only_stock ) { 258 /** 259 * Send api request to update the price 260 */ 261 $pricing_api->execute( $this->pricing_update ); 262 } 263 264 /** 265 * Send api request to update the inventory 266 */ 267 $inventory_api->execute( $this->inventory_update ); 268 } 269 } 270 271 /** 272 * @param Product $product 273 * 274 * @psalm-suppress all 275 */ 276 public function update_normal_product( $product ) { 277 if ( empty( $product->get_sku() ) ) { 278 ShoppingFeedHelper::get_logger()->warning( 279 sprintf( 280 /* translators: %s: Product ID. */ 281 __( 'Cant update product without SKU => %s', 'shopping-feed' ), 282 $product->get_wc_product()->get_id() 283 ), 284 array( 285 'source' => 'shopping-feed', 286 ) 287 ); 288 289 return false; 290 } 291 292 $this->may_update_pricing( $product->get_sku(), ! empty( $product->get_discount() ) ? $product->get_discount() : $product->get_price() ); 293 $this->may_update_inventory( $product->get_sku(), $product->get_quantity() ); 294 295 return true; 296 } 297 298 /** 299 * @param Product $product 300 * 301 * @psalm-suppress all 302 * @return bool 303 */ 304 public function update_variation_product( $product ) { 305 foreach ( $product->get_variations() as $variation ) { 306 if ( empty( $variation['sku'] ) ) { 307 ShoppingFeedHelper::get_logger()->warning( 308 sprintf( 309 /* translators: %s: Product ID. */ 310 __( 'Cant update product without SKU => %s', 'shopping-feed' ), 311 $product->get_wc_product()->get_id() 312 ), 313 array( 314 'source' => 'shopping-feed', 315 ) 316 ); 236 317 237 318 return false; 238 319 } 239 320 240 $this->may_update_pricing( $product->get_sku(), ! empty( $product->get_discount() ) ? $product->get_discount() : $product->get_price() ); 241 $this->may_update_inventory( $product->get_sku(), $product->get_quantity() ); 242 } 243 /** 244 * Check if we need to update the price or only the stock 245 */ 246 if ( ! $only_stock ) { 247 /** 248 * Send api request to update the price 249 */ 250 $pricing_api->execute( $this->pricing_update ); 251 } 252 253 /** 254 * Send api request to update the inventory 255 */ 256 $inventory_api->execute( $this->inventory_update ); 321 $this->may_update_pricing( $variation['sku'], ! empty( $variation['discount'] ) ? $variation['discount'] : $variation['price'] ); 322 $this->may_update_inventory( $variation['sku'], $variation['quantity'] ); 323 } 257 324 258 325 return true; … … 306 373 $this->inventory_update->add( $sku, intval( $inventory ) ); 307 374 } 375 376 /** 377 * @return bool 378 * @throws Exception 379 * @psalm-suppress all 380 */ 381 public function migrate_old_accounts() { 382 //migrate account data and retrieve account ID 383 $account_options = ShoppingFeedHelper::get_sf_account_options(); 384 385 if ( empty( $account_options['token'] ) ) { 386 ShoppingFeedHelper::get_logger()->error( 387 sprintf( 388 __( 'No token founds', 'shopping-feed' ) 389 ), 390 array( 391 'source' => 'shopping-feed', 392 ) 393 ); 394 ShoppingFeedHelper::end_upgrade(); 395 396 return false; 397 } 398 try { 399 $main_store = Client\Client::createSession( new Credential\Token( $account_options['token'] ) )->getMainStore(); 400 if ( is_null( $main_store ) ) { 401 ShoppingFeedHelper::get_logger()->error( 402 sprintf( 403 __( 'Cant retrieve main store', 'shopping-feed' ) 404 ), 405 array( 406 'source' => 'shopping-feed', 407 ) 408 ); 409 410 ShoppingFeedHelper::end_upgrade(); 411 412 return false; 413 } 414 $account_id = $main_store->getId(); 415 $new_account_options = array(); 416 $new_account_options[] = array( 417 'sf_store_id' => $account_id, 418 'username' => ! empty( $account_options['username'] ) ? $account_options['username'] : '', 419 'password' => ! empty( $account_options['password'] ) ? $account_options['password'] : '', 420 'token' => $account_options['token'], 421 ); 422 ShoppingFeedHelper::set_sf_account_options( $new_account_options ); 423 } catch ( \Exception $exception ) { 424 ShoppingFeedHelper::get_logger()->error( 425 sprintf( 426 /* translators: %s: Error message. */ 427 __( 'Cant login with actual credentials => %s', 'shopping-feed' ), 428 $exception->getMessage() 429 ), 430 array( 431 'source' => 'shopping-feed', 432 ) 433 ); 434 435 ShoppingFeedHelper::end_upgrade(); 436 437 return false; 438 } 439 440 //Migrate old orders to default account 441 $args = array( 442 'limit' => - 1, 443 'meta_key' => Query::WC_META_SF_REFERENCE, 444 'meta_compare' => 'EXISTS', 445 ); 446 447 $query = new \WC_Order_Query( $args ); 448 $wc_orders = $query->get_orders(); 449 if ( empty( $wc_orders ) ) { 450 ShoppingFeedHelper::get_logger()->error( 451 sprintf( 452 __( 'No SF orders founds for migration', 'shopping-feed' ) 453 ), 454 array( 455 'source' => 'shopping-feed', 456 ) 457 ); 458 ShoppingFeedHelper::end_upgrade(); 459 460 return false; 461 } 462 463 foreach ( $wc_orders as $wc_order ) { 464 //add store id 465 /** @var \WC_Order $wc_order */ 466 $wc_order->add_meta_data( Query::WC_META_SF_STORE_ID, $account_id ); 467 $wc_order->save(); 468 } 469 470 ShoppingFeedHelper::end_upgrade(); 471 472 return true; 473 } 308 474 } -
shopping-feed/trunk/src/Feed/Generator.php
r2542211 r2670662 234 234 235 235 if ( true === $no_cache || ! is_file( $file_path ) ) { 236 if ( ShoppingFeedHelper:: generation_process_running() ) {236 if ( ShoppingFeedHelper::is_process_running( 'sf_feed_generation_process' ) ) { 237 237 wp_die( 'Feed generation already launched' ); 238 238 } -
shopping-feed/trunk/src/Orders/Operations.php
r2542211 r2670662 53 53 */ 54 54 public function __construct( $order_id ) { 55 $sdk = Sdk::get_instance(); 56 if ( ! $sdk->get_default_shop() instanceof StoreResource ) { 55 //Check if the order from SF and return it with metas data 56 $order_sf_metas = Order::get_order_sf_metas( $order_id ); 57 if ( 58 empty( $order_sf_metas ) || 59 empty( $order_sf_metas['sf_store_id'] ) 60 ) { 61 throw new Exception( 62 sprintf( 63 /* translators: %s: Error message. */ 64 __( 'No SF order found in %s', 'shopping-feed' ), 65 $order_id 66 ) 67 ); 68 } 69 70 $account_id = $order_sf_metas['sf_store_id']; 71 72 $shop = Sdk::get_sf_account_shop( $account_id ); 73 74 if ( ! $shop instanceof StoreResource ) { 75 ShoppingFeedHelper::get_logger()->error( 76 sprintf( 77 /* translators: %s: Error message. */ 78 __( 'Cannot retrieve shop from SDK for account : %s', 'shopping-feed' ), 79 $account_id 80 ), 81 array( 82 'source' => 'shopping-feed', 83 ) 84 ); 57 85 throw new Exception( 58 86 __( 'No store found', 'shopping-feed' ) 59 87 ); 60 88 } 61 /** @var StoreResource $default_shop */62 $default_shop = $sdk->get_default_shop();63 64 //Check if the order from SF and return it with metas data65 $order_sf_metas = Order::get_order_sf_metas( $order_id );66 if ( empty( $order_sf_metas ) ) {67 throw new Exception(68 __( 'No Order found', 'shopping-feed' )69 );70 }71 89 72 90 $this->wc_order = $order_sf_metas['order']; 73 $this->order_api = $ default_shop->getOrderApi();91 $this->order_api = $shop->getOrderApi(); 74 92 $this->order_operation = new OrderOperation(); 75 93 $this->sf_reference = (string) $order_sf_metas['sf_reference']; -
shopping-feed/trunk/src/Orders/Order.php
r2551274 r2670662 221 221 */ 222 222 public static function exists( $sf_order ) { 223 return ! empty( wc_get_orders( array( Query:: $wc_meta_sf_reference=> $sf_order->getReference() ) ) );223 return ! empty( wc_get_orders( array( Query::WC_META_SF_REFERENCE => $sf_order->getReference() ) ) ); 224 224 } 225 225 … … 313 313 } 314 314 315 $sf_reference = $order->get_meta( Query::$wc_meta_sf_reference ); 316 $sf_channel_name = $order->get_meta( Query::$wc_meta_sf_channel_name ); 315 $sf_store_id = $order->get_meta( Query::WC_META_SF_STORE_ID ); 316 $sf_reference = $order->get_meta( Query::WC_META_SF_REFERENCE ); 317 $sf_channel_name = $order->get_meta( Query::WC_META_SF_CHANNEL_NAME ); 317 318 318 319 return array( 319 320 'order' => $order, 321 'sf_store_id' => $sf_store_id, 320 322 'sf_reference' => $sf_reference, 321 323 'sf_channel_name' => $sf_channel_name, … … 336 338 } 337 339 338 return ! empty( $wc_order->get_meta( Query:: $wc_meta_sf_reference) );340 return ! empty( $wc_order->get_meta( Query::WC_META_SF_REFERENCE ) ); 339 341 } 340 342 … … 347 349 */ 348 350 public static function can_update_stock( $wc_order ) { 349 return empty( $wc_order->get_meta( Query:: $wc_meta_sf_reference) ) || empty( $wc_order->get_meta( Metas::$dont_update_inventory ) );351 return empty( $wc_order->get_meta( Query::WC_META_SF_REFERENCE ) ) || empty( $wc_order->get_meta( Metas::$dont_update_inventory ) ); 350 352 } 351 353 } -
shopping-feed/trunk/src/Orders/Order/Metas.php
r2339808 r2670662 39 39 $this->add_order_channel_name(); 40 40 $this->add_order_shipping(); 41 $this->add_sf_store_id(); 41 42 42 43 do_action_ref_array( 'sf_add_metas', array( $this ) ); … … 47 48 */ 48 49 private function add_order_referene() { 49 $this->add_meta( Query:: $wc_meta_sf_reference, $this->sf_order->getReference(), true );50 $this->add_meta( Query::WC_META_SF_REFERENCE, $this->sf_order->getReference(), true ); 50 51 } 51 52 … … 54 55 */ 55 56 private function add_order_channel_name() { 56 $this->add_meta( Query:: $wc_meta_sf_channel_name, $this->sf_order->getChannel()->getName() );57 $this->add_meta( Query::WC_META_SF_CHANNEL_NAME, $this->sf_order->getChannel()->getName() ); 57 58 } 58 59 … … 81 82 ); 82 83 } 84 85 /** 86 * Add store id 87 */ 88 private function add_sf_store_id() { 89 $sf_order_array = $this->sf_order->toArray(); 90 $this->add_meta( Query::WC_META_SF_STORE_ID, $sf_order_array['storeId'] ); 91 } 83 92 } -
shopping-feed/trunk/src/Orders/Orders.php
r2417980 r2670662 14 14 */ 15 15 class Orders { 16 17 /**18 * @var false|StoreResource19 */20 private $shop;21 16 22 17 /** … … 51 46 52 47 /** 53 * Orders constructor.48 * Get Orders from SF 54 49 */ 55 private function __construct() { 56 if ( empty( $this->shop ) ) { 57 $sdk = Sdk::get_instance(); 58 if ( $sdk->get_default_shop() ) { 59 $this->shop = $sdk->get_default_shop(); 60 } 61 } 62 } 50 public function get_orders( $sf_account ) { 51 $shop = Sdk::get_sf_shop( $sf_account ); 63 52 64 /** 65 * Get Orders from SF 66 * @return bool 67 */ 68 public function get_orders() { 69 if ( ! $this->shop ) { 53 if ( ! $shop instanceof StoreResource ) { 54 ShoppingFeedHelper::get_logger()->error( 55 sprintf( 56 /* translators: %s: Error message. */ 57 __( 'Cannot retrieve shop from SDK for account : %s', 'shopping-feed' ), 58 $sf_account['username'] 59 ), 60 array( 61 'source' => 'shopping-feed', 62 ) 63 ); 70 64 return false; 71 65 } 72 66 73 $order_api = $ this->shop->getOrderApi();67 $order_api = $shop->getOrderApi(); 74 68 $filters = array(); 75 69 $filters['acknowledgment'] = 'unacknowledged'; -
shopping-feed/trunk/src/Products/Product.php
r2487968 r2670662 48 48 49 49 return $this; 50 } 51 52 /** 53 * Return WC Product 54 * @return false|\WC_Product|null 55 */ 56 public function get_wc_product() { 57 return $this->product; 50 58 } 51 59 -
shopping-feed/trunk/src/Query/Query.php
r2339808 r2670662 10 10 */ 11 11 class Query { 12 /** 13 * Custom Meta for SF accpunt ID 14 */ 15 const WC_META_SF_STORE_ID = 'sf_store_id'; 12 16 13 17 /** 14 18 * Custom Meta for SF reference 15 * @var string16 19 */ 17 public static $wc_meta_sf_reference= 'sf_reference';20 const WC_META_SF_REFERENCE = 'sf_reference'; 18 21 19 22 /** 20 23 * Custom Meta for SF channel name 21 * @var string22 24 */ 23 public static $wc_meta_sf_channel_name= 'sf_marketplace';25 const WC_META_SF_CHANNEL_NAME = 'sf_marketplace'; 24 26 25 27 public function __construct() { … … 44 46 */ 45 47 public function wc_get_by_sf_reference( $query, $query_vars ) { 46 if ( ! empty( $query_vars[ self:: $wc_meta_sf_reference] ) ) {48 if ( ! empty( $query_vars[ self::WC_META_SF_REFERENCE ] ) ) { 47 49 $query['meta_query'][] = array( 48 'key' => self:: $wc_meta_sf_reference,49 'value' => esc_attr( $query_vars[ self:: $wc_meta_sf_reference] ),50 'key' => self::WC_META_SF_REFERENCE, 51 'value' => esc_attr( $query_vars[ self::WC_META_SF_REFERENCE ] ), 50 52 ); 51 53 } -
shopping-feed/trunk/src/Sdk/Sdk.php
r2417980 r2670662 6 6 defined( 'ABSPATH' ) || exit; 7 7 8 use ShoppingFeed\Sdk\Api\Session\SessionResource;9 8 use ShoppingFeed\Sdk\Client; 10 9 use ShoppingFeed\Sdk\Credential; … … 16 15 class Sdk { 17 16 18 /** @var SessionResource */ 19 private $session; 17 /** 18 * @param int $account_id 19 */ 20 public static function get_sf_account_shop( $account_id ) { 21 $sf_account = ShoppingFeedHelper::get_sf_account_credentials( $account_id ); 20 22 21 /** @var string|null */22 private $username;23 return self::get_sf_shop( $sf_account ); 24 } 23 25 24 /** @var string|null */25 private $password;26 27 /** @var string|null */28 private $token;29 26 30 27 /** 31 * @var Sdk 28 * Return account deault shop 29 * 30 * @param array $sf_account 31 * 32 * @return false|\ShoppingFeed\Sdk\Api\Store\StoreResource 33 * @psalm-suppress all 32 34 */ 33 private static $instance; 34 35 /** 36 * Get the singleton instance. 37 * 38 * @return Sdk 39 */ 40 public static function get_instance() { 41 if ( is_null( self::$instance ) ) { 42 self::$instance = new static(); 43 } 44 45 return self::$instance; 46 } 47 48 /** 49 * Singleton instance can't be cloned. 50 */ 51 private function __clone() { 52 } 53 54 /** 55 * Singleton instance can't be serialized. 56 */ 57 private function __wakeup() { 58 } 59 60 /** 61 * Sdk constructor. 62 */ 63 private function __construct() { 64 if ( empty( $this->session ) ) { 65 $options = ShoppingFeedHelper::get_sf_account_options(); 66 if ( empty( $options ) ) { 67 ShoppingFeedHelper::get_logger()->error( 68 __( 'No settings founds', 'shopping-feed' ), 69 array( 70 'source' => 'shopping-feed', 71 ) 72 ); 73 74 return; 75 } 76 77 $this->token = ! empty( $options['token'] ) ? $options['token'] : null; 78 $this->username = ! empty( $options['username'] ) ? $options['username'] : null; 79 $this->password = ! empty( $options['password'] ) ? $options['password'] : null; 80 81 $this->authenticate(); 82 } 83 } 84 85 /** 86 * @return Credential\Password|Credential\Token|\WP_Error 87 */ 88 private function get_credential() { 89 90 //Check if we have Token to connect directly 91 if ( ! empty( $this->token ) ) { 92 return new Credential\Token( $this->token ); 93 } 94 95 //If no credentials found go back 96 if ( empty( $this->username ) || empty( $this->password ) ) { 35 public static function get_sf_shop( $sf_account ) { 36 if ( 37 empty( $sf_account['token'] ) && ( 38 empty( $sf_account['username'] ) || 39 empty( $sf_account['password'] ) 40 ) 41 ) { 42 //TODO: add more informations about concerned sf account 97 43 ShoppingFeedHelper::get_logger()->error( 98 __( 'Need username/password to connect', 'shopping-feed' ), 44 sprintf( 45 __( 'No Credentials found to connect', 'shopping-feed' ) 46 ), 99 47 array( 100 48 'source' => 'shopping-feed', 101 49 ) 102 50 ); 103 return new \WP_Error( 'shopping_feed_auth_required', __( 'Need username/password to connect', 'shopping-feed' ) );104 }105 51 106 //Return Credentials username/password107 return new Credential\Password( $this->username, $this->password );108 }109 110 /**111 * Try to connect if we have credentials112 * Set Token if the connection is set113 * @return bool114 */115 public function authenticate() {116 if ( is_wp_error( $this->get_credential() ) ) {117 52 return false; 118 53 } 119 54 120 /** @var Credential\Password|Credential\Token $credentials */ 121 $credentials = $this->get_credential(); 55 $credentials = new Credential\Password( $sf_account['username'], $sf_account['password'] ); 56 57 if ( ! empty( $sf_account['token'] ) ) { 58 $credentials = new Credential\Token( $sf_account['token'] ); 59 } 122 60 123 61 try { 124 $this->session = Client\Client::createSession( $credentials ); 125 126 if ( empty( $this->token ) ) { 127 ShoppingFeedHelper::set_sf_token( $this->session->getToken() ); 128 } 129 130 return true; 62 $session = Client\Client::createSession( $credentials ); 131 63 } catch ( \Exception $exception ) { 132 133 64 ShoppingFeedHelper::get_logger()->error( 134 65 sprintf( … … 142 73 ); 143 74 144 ShoppingFeedHelper::clean_password();145 return false;146 }147 }148 149 /**150 * Return the main store if the connection is set151 * @return false|\ShoppingFeed\Sdk\Api\Store\StoreResource152 */153 public function get_default_shop() {154 155 if ( ! $this->authenticate() ) {156 75 return false; 157 76 } 158 77 159 $main_shop = $ this->session->getMainStore();78 $main_shop = $session->getMainStore(); 160 79 161 if ( ! $main_shop) {80 if ( empty( $main_shop ) ) { 162 81 ShoppingFeedHelper::get_logger()->error( 82 //TODO: add more informations about concerned sf account 163 83 __( 'No store found', 'shopping-feed' ), 164 84 array( … … 166 86 ) 167 87 ); 88 168 89 return false; 169 90 } 91 92 //add storeId to account 93 $account_options = ShoppingFeedHelper::get_sf_account_options(); 94 $index = array_search( $sf_account['username'], array_column( $account_options, 'username' ), true ); 95 if ( false === $index || empty( $account_options[ $index ] ) ) { 96 return false; 97 } 98 $account_options[ $index ]['sf_store_id'] = $main_shop->getId(); 99 $account_options[ $index ]['token'] = $session->getToken(); 100 ShoppingFeedHelper::set_sf_account_options( $account_options ); 170 101 171 102 return $main_shop; -
shopping-feed/trunk/src/ShoppingFeed.php
r2542211 r2670662 117 117 } 118 118 119 $this->actions = new WoocommerceActions(); 120 121 //Check Upgrade 122 if ( ! $this->check_upgrade() ) { 123 return; 124 } 125 119 126 $this->query = new Query(); 120 $this->actions = new WoocommerceActions();121 127 $this->filters = new WoocommerceFilters(); 122 128 $this->notices = new Notices(); … … 242 248 delete_option( Options::SF_CARRIERS ); 243 249 delete_option( Generator::SF_FEED_LAST_GENERATION_DATE ); 250 delete_option( SF_DB_VERSION_SLUG ); 251 delete_option( SF_UPGRADE_RUNNING ); 244 252 self::remove_sf_directory(); 245 253 } … … 259 267 } 260 268 } 269 270 public function check_upgrade() { 271 if ( ! ShoppingFeedHelper::sf_has_upgrade() || ShoppingFeedHelper::sf_new_customer() ) { 272 return true; 273 } 274 275 //check if we have a running migration 276 if ( ShoppingFeedHelper::is_upgrade_running() ) { 277 add_action( 278 'admin_notices', 279 function () { 280 ?> 281 <div id="message" class="notice notice-error"> 282 <p><?php esc_html_e( 'ShoppingFeed migration is running', 'shopping-feed' ); ?></p> 283 </div> 284 <?php 285 } 286 ); 287 288 return false; 289 } 290 291 //check if we need to do migration 292 if ( 293 ! empty( $_GET['sf_action'] ) && 294 'sf_migrate_single' === $_GET['sf_action'] && 295 isset( $_GET['_wpnonce'] ) && 296 wp_verify_nonce( wp_unslash( $_GET['_wpnonce'] ), 'sf_migrate_single' ) // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized 297 ) { 298 $id_action = as_enqueue_async_action( 'sf_migrate_single_action', array(), 'sf_migrate_single' ); 299 update_option( SF_UPGRADE_RUNNING, $id_action ); 300 wp_safe_redirect( admin_url( '/' ), 302 ); 301 exit; 302 } 303 304 add_action( 305 'admin_notices', 306 function () { 307 ?> 308 <div id="message" class="notice notice-error"> 309 <p><?php esc_html_e( 'ShoppingFeed need to migrate old data', 'shopping-feed' ); ?></p> 310 <a href=" 311 <?php 312 echo esc_url( 313 wp_nonce_url( 314 add_query_arg( 315 array( 316 'sf_action' => 'sf_migrate_single', 317 ), 318 admin_url() 319 ), 320 'sf_migrate_single' 321 ) 322 ) 323 ?> 324 ">Migrate</a> 325 </div> 326 <?php 327 } 328 ); 329 330 return false; 331 } 261 332 } -
shopping-feed/trunk/src/ShoppingFeedHelper.php
r2560053 r2670662 7 7 8 8 use ShoppingFeed\ShoppingFeedWC\Admin\Options; 9 use ShoppingFeed\ShoppingFeedWC\Sdk\Sdk;10 9 use ShoppingFeed\ShoppingFeedWC\Url\Rewrite; 11 10 use WC_Logger; … … 141 140 142 141 /** 143 * Set SF token after connection144 *145 * @param $token146 *147 */148 public static function set_sf_token( $token ) {149 $options = self::get_sf_account_options();150 $options['token'] = $token;151 152 update_option( Options::SF_ACCOUNT_OPTIONS, $options );153 }154 155 /**156 142 * Return SF Configuration for Account 157 * @return mixed|void143 * @return array 158 144 */ 159 145 public static function get_sf_account_options() { 160 return get_option( Options::SF_ACCOUNT_OPTIONS ); 161 } 162 163 /** 164 * Reset password if bad 165 * 166 * @param $token 167 * 168 */ 169 public static function clean_password() { 170 $options = self::get_sf_account_options(); 171 if ( isset( $options ) && isset( $options['password'] ) ) { 172 unset( $options['password'] ); 173 } 174 175 update_option( Options::SF_ACCOUNT_OPTIONS, $options ); 146 return get_option( Options::SF_ACCOUNT_OPTIONS, array() ); 147 } 148 149 150 /** 151 * Set SF Configuration for Account 152 * @return bool 153 */ 154 public static function set_sf_account_options( $option ) { 155 return update_option( Options::SF_ACCOUNT_OPTIONS, $option ); 156 } 157 158 /** 159 * @param $account_id 160 * @psalm-suppress all 161 * @return array 162 */ 163 public static function get_sf_account_credentials( $account_id ) { 164 $account_options = self::get_sf_account_options(); 165 $index = array_search( (int) $account_id, array_column( $account_options, 'sf_store_id' ), true ); 166 if ( false === $index || empty( $account_options[ $index ] ) ) { 167 return array(); 168 } 169 170 return $account_options[ $index ]; 176 171 } 177 172 … … 566 561 567 562 /** 568 * @return bool569 */570 public static function is_authenticated() {571 $sdk = Sdk::get_instance();572 if ( empty( $sdk ) ) {573 return false;574 }575 576 return $sdk->authenticate();577 }578 579 /**580 563 * Add filter for category taxonomy 581 564 * default: product_cat … … 662 645 /** 663 646 * Check if a running generation process 647 * 648 * @param $group 649 * 664 650 * @return bool 665 651 */ 666 public static function generation_process_running() {667 $process = self::get_running_ generation_feed_process();652 public static function is_process_running( $group ) { 653 $process = self::get_running_process( $group ); 668 654 669 655 return ! empty( $process ); … … 672 658 /** 673 659 * Get running process list 660 * 661 * @param string $group 662 * 674 663 * @return array|int 675 664 */ 676 public static function get_running_ generation_feed_process() {665 public static function get_running_process( $group ) { 677 666 $action_scheduler = \ActionScheduler::store(); 678 667 679 668 return $action_scheduler->query_actions( 680 669 array( 681 'group' => 'sf_feed_generation_process',670 'group' => $group, 682 671 'status' => $action_scheduler::STATUS_PENDING, 683 672 ) … … 685 674 } 686 675 687 public static function clean_generation_process_running() { 676 /** 677 * @param string $group 678 */ 679 public static function clean_process_running( $group ) { 688 680 try { 689 \ActionScheduler::store()->cancel_actions_by_group( 'sf_feed_generation_process');681 \ActionScheduler::store()->cancel_actions_by_group( $group ); 690 682 } catch ( \Exception $exception ) { 691 683 self::get_logger()->error( … … 732 724 733 725 /** 726 * Check if new customer 727 * @return bool 728 */ 729 public static function sf_new_customer() { 730 return empty( get_option( Options::SF_ACCOUNT_OPTIONS ) ) && 731 empty( get_option( Options::SF_FEED_OPTIONS ) ) && 732 empty( get_option( Options::SF_SHIPPING_OPTIONS ) ) && 733 empty( get_option( Options::SF_ORDERS_OPTIONS ) ); 734 } 735 736 /** 734 737 * Singleton instance can't be cloned. 735 738 */ … … 742 745 private function __wakeup() { 743 746 } 747 748 /** 749 * Check if we have an upgrade 750 * @return bool 751 */ 752 public static function sf_has_upgrade() { 753 754 $db_version = get_option( SF_DB_VERSION_SLUG ); 755 756 return empty( $db_version ) || version_compare( $db_version, SF_DB_VERSION, '<' ); 757 } 758 759 /** 760 * Check if we have a running upgrade 761 * @return bool 762 */ 763 public static function is_upgrade_running() { 764 return ! empty( get_option( SF_UPGRADE_RUNNING ) ); 765 } 766 767 /* 768 * End upgrade 769 */ 770 public static function end_upgrade() { 771 delete_option( SF_UPGRADE_RUNNING ); 772 update_option( SF_DB_VERSION_SLUG, SF_DB_VERSION ); 773 } 744 774 } -
shopping-feed/trunk/vendor/autoload.php
r2613147 r2670662 5 5 require_once __DIR__ . '/composer/autoload_real.php'; 6 6 7 return ComposerAutoloaderInit 8e1243f94001ab8dc300d6b62efdcaf0::getLoader();7 return ComposerAutoloaderInit0002ac7dfac052b9a9cc79f1494358a4::getLoader(); -
shopping-feed/trunk/vendor/composer/ClassLoader.php
r2602861 r2670662 150 150 /** 151 151 * @return string[] Array of classname => path 152 * @psalm- vararray<string, string>152 * @psalm-return array<string, string> 153 153 */ 154 154 public function getClassMap() -
shopping-feed/trunk/vendor/composer/InstalledVersions.php
r2602861 r2670662 25 25 class InstalledVersions 26 26 { 27 /** 28 * @var mixed[]|null 29 * @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null 30 */ 27 31 private static $installed; 32 33 /** 34 * @var bool|null 35 */ 28 36 private static $canGetVendors; 37 38 /** 39 * @var array[] 40 * @psalm-var array<string, array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}> 41 */ 29 42 private static $installedByVendor = array(); 30 43 -
shopping-feed/trunk/vendor/composer/autoload_real.php
r2613147 r2670662 3 3 // autoload_real.php @generated by Composer 4 4 5 class ComposerAutoloaderInit 8e1243f94001ab8dc300d6b62efdcaf05 class ComposerAutoloaderInit0002ac7dfac052b9a9cc79f1494358a4 6 6 { 7 7 private static $loader; … … 23 23 } 24 24 25 spl_autoload_register(array('ComposerAutoloaderInit 8e1243f94001ab8dc300d6b62efdcaf0', 'loadClassLoader'), true, true);25 spl_autoload_register(array('ComposerAutoloaderInit0002ac7dfac052b9a9cc79f1494358a4', 'loadClassLoader'), true, true); 26 26 self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__))); 27 spl_autoload_unregister(array('ComposerAutoloaderInit 8e1243f94001ab8dc300d6b62efdcaf0', 'loadClassLoader'));27 spl_autoload_unregister(array('ComposerAutoloaderInit0002ac7dfac052b9a9cc79f1494358a4', 'loadClassLoader')); 28 28 29 29 $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); … … 31 31 require __DIR__ . '/autoload_static.php'; 32 32 33 call_user_func(\Composer\Autoload\ComposerStaticInit 8e1243f94001ab8dc300d6b62efdcaf0::getInitializer($loader));33 call_user_func(\Composer\Autoload\ComposerStaticInit0002ac7dfac052b9a9cc79f1494358a4::getInitializer($loader)); 34 34 } else { 35 35 $map = require __DIR__ . '/autoload_namespaces.php'; … … 52 52 53 53 if ($useStaticLoader) { 54 $includeFiles = Composer\Autoload\ComposerStaticInit 8e1243f94001ab8dc300d6b62efdcaf0::$files;54 $includeFiles = Composer\Autoload\ComposerStaticInit0002ac7dfac052b9a9cc79f1494358a4::$files; 55 55 } else { 56 56 $includeFiles = require __DIR__ . '/autoload_files.php'; 57 57 } 58 58 foreach ($includeFiles as $fileIdentifier => $file) { 59 composerRequire 8e1243f94001ab8dc300d6b62efdcaf0($fileIdentifier, $file);59 composerRequire0002ac7dfac052b9a9cc79f1494358a4($fileIdentifier, $file); 60 60 } 61 61 … … 64 64 } 65 65 66 function composerRequire8e1243f94001ab8dc300d6b62efdcaf0($fileIdentifier, $file) 66 /** 67 * @param string $fileIdentifier 68 * @param string $file 69 * @return void 70 */ 71 function composerRequire0002ac7dfac052b9a9cc79f1494358a4($fileIdentifier, $file) 67 72 { 68 73 if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { 74 $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; 75 69 76 require $file; 70 71 $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;72 77 } 73 78 } -
shopping-feed/trunk/vendor/composer/autoload_static.php
r2613147 r2670662 5 5 namespace Composer\Autoload; 6 6 7 class ComposerStaticInit 8e1243f94001ab8dc300d6b62efdcaf07 class ComposerStaticInit0002ac7dfac052b9a9cc79f1494358a4 8 8 { 9 9 public static $files = array ( … … 439 439 { 440 440 return \Closure::bind(function () use ($loader) { 441 $loader->prefixLengthsPsr4 = ComposerStaticInit 8e1243f94001ab8dc300d6b62efdcaf0::$prefixLengthsPsr4;442 $loader->prefixDirsPsr4 = ComposerStaticInit 8e1243f94001ab8dc300d6b62efdcaf0::$prefixDirsPsr4;443 $loader->classMap = ComposerStaticInit 8e1243f94001ab8dc300d6b62efdcaf0::$classMap;441 $loader->prefixLengthsPsr4 = ComposerStaticInit0002ac7dfac052b9a9cc79f1494358a4::$prefixLengthsPsr4; 442 $loader->prefixDirsPsr4 = ComposerStaticInit0002ac7dfac052b9a9cc79f1494358a4::$prefixDirsPsr4; 443 $loader->classMap = ComposerStaticInit0002ac7dfac052b9a9cc79f1494358a4::$classMap; 444 444 445 445 }, null, ClassLoader::class); -
shopping-feed/trunk/vendor/composer/installed.php
r2613147 r2670662 1 1 <?php return array( 2 2 'root' => array( 3 'pretty_version' => '6. 0.33',4 'version' => '6. 0.33.0',3 'pretty_version' => '6.1.0', 4 'version' => '6.1.0.0', 5 5 'type' => 'wordpress-plugin', 6 6 'install_path' => __DIR__ . '/../../', 7 7 'aliases' => array(), 8 'reference' => ' b54ebdf093f62b8a77538414cf5a4eb070cd1bb5',8 'reference' => '7457e98e9f4b6982416834d213cea5359612cfd9', 9 9 'name' => 'shoppingfeed/shoppingfeed', 10 10 'dev' => false, … … 102 102 ), 103 103 'shoppingfeed/shoppingfeed' => array( 104 'pretty_version' => '6. 0.33',105 'version' => '6. 0.33.0',104 'pretty_version' => '6.1.0', 105 'version' => '6.1.0.0', 106 106 'type' => 'wordpress-plugin', 107 107 'install_path' => __DIR__ . '/../../', 108 108 'aliases' => array(), 109 'reference' => ' b54ebdf093f62b8a77538414cf5a4eb070cd1bb5',109 'reference' => '7457e98e9f4b6982416834d213cea5359612cfd9', 110 110 'dev_requirement' => false, 111 111 ),
Note: See TracChangeset
for help on using the changeset viewer.