Commit 04f1d040 by Damien Moulard

fix merge conflicts

parents 97762d78 8be42f4b
......@@ -47,6 +47,8 @@ PAYZEN_DEBUG=false
### TAV ###
TAV_ENV=0
PRESTA_SELF_INIT_AND_EVAL=0
AUTOMATISATION_RECONVERSION=0
PRESTA_EXTRA_DATA=0
EMAIL_ERROR=technique@kohinos.net
EMAIL_USER_FROM=noreply@kohinos.fr
......
......@@ -54,6 +54,8 @@ Copier le fichier .env.dist en .env et configurer :
- la variable APP_SECRET (variable secrète que vous pouvez générer à partir de cette url : http://nux.net/secret
- s'il s'agit d'une instance TAV, mettre la variable TAV_ENV à 1 (sinon la laisser à zéro)
- en environnement TAV, pour activer le parcours d'inscription autonomisé qui intègre la réponse à une questionnaire d'auto-évaluation pour les points de vente, passer PRESTA_SELF_INIT_AND_EVAL à 1
- en environnement TAV, la variable AUTOMATISATION_RECONVERSION permet d'activer l'automatisation des reconversions
- en environnement TAV, la variable PRESTA_EXTRA_DATA permet d'indiquer puis d'afficher publiquement plus de données concernant les prestataires (e.g. familles de produits)
Si vous utilisez Payzen comme moyen de paiement par CB :
......
......@@ -291,6 +291,10 @@ form[name="formEncaissement"] label {
}
}
/**
* END Success check animation.
*/
#login-password-container {
position: relative;
}
......@@ -345,9 +349,52 @@ form[name="formEncaissement"] label {
* END Success check animation.
*/
.prestaquizz_temporary_save_container {
.prestaquizz_temporary_save_container {
position: fixed;
bottom: 0;
right: 1rem;
z-index: 2;
}
\ No newline at end of file
}
.presta-products-family {
display: flex;
margin-bottom: 1rem;
}
.presta-products-family-fields {
width: 95%;
}
.presta-products-family-delete {
width: 5%;
text-align: end;
}
.presta-products-family-form-group {
display: flex;
gap: 5px;
align-items: center;
margin-bottom: 0.25rem !important;
}
.presta-products-family-form-group label {
width: 40%;
margin-bottom: 0;
}
.delete-icon {
color: #ff4136;
}
.delete-icon:hover {
cursor: pointer;
color: #a02923;
}
.presta-products-family-duplicate-warning {
display: none;
color: #ff4136;
margin-top: -0.25rem;
text-align: right;
font-style: italic;
}
......@@ -70,7 +70,7 @@ $(document).ready(function() {
});
});
// Hide or display Cotisation or Profils de Cotisation submenu depending on TAV env
// Hide or display Cotisation, Profils de Cotisation and Products Families submenu depending on TAV env
const tav_env = document.getElementsByName('is-tav-env')[0].getAttribute('content');
let linksToCotisationAdherent = $('a[href="/admin/cotisation_adherent/list"]');
......@@ -91,6 +91,12 @@ $(document).ready(function() {
linksToProfilDeCotisation[i].parentNode.style.display = (tav_env === "1") ? "" : "none";
}
}
let linksToProductsFamily = $('a[href="/admin/app/productfamily/list"]');
for(let i = 0 ; i < linksToProductsFamily.length ; i++) {
if(linksToProductsFamily[i].innerText === "Familles de produits") {
linksToProductsFamily[i].parentNode.style.display = (tav_env === "1") ? "" : "none";
}
}
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
......
......@@ -649,4 +649,74 @@ $(function() {
$('form[name="formDistributorSelfEvalPrestaQuiz"]').trigger("submit");
});
/**
* Delete a PrestataireProductFamily node on icon click
* @param {Event} e
*/
function deletePrestataireProductFamily(e) {
e.preventDefault();
$(this).closest('.presta-products-family')
.fadeOut()
.remove();
}
$(".presta-products-family-delete").on("click", deletePrestataireProductFamily);
/**
* Check if a product family is already selected on select change.
*/
function onPrestataireProductFamilyChange() {
let current_select_id = $(this).attr('id');
let current_select_selected_option = $( `#${current_select_id} option:selected` ).text();
let same_selected_option = false;
$('.prestataire-product-families-select').each(function() {
let select_id = $(this).attr('id');
let select_selected_option = $( `#${select_id} option:selected` ).text();
if (current_select_id !== select_id && current_select_selected_option === select_selected_option) {
same_selected_option = true;
return false;
}
});
$('.presta-products-family-fields .presta-products-family-duplicate-warning').hide();
$('.prestataire-product-families-products').attr('disabled', false);
if (same_selected_option) {
$(this).closest('.presta-products-family-fields').find('.presta-products-family-duplicate-warning').show();
$(this).closest('.presta-products-family-fields').find('.prestataire-product-families-products').attr('disabled', true);
}
}
$('.prestataire-product-families-select').on('change', onPrestataireProductFamilyChange);
/**
* Twig helper, add element to Collection in template based on collection prototype
* @param {*} e
*/
function addFormToCollection(e) {
const collectionHolder = document.querySelector('.' + e.currentTarget.dataset.collectionHolderClass);
const item = document.createElement('div');
item.innerHTML = collectionHolder
.dataset
.prototype
.replace(
/__name__/g,
collectionHolder.dataset.index
);
collectionHolder.appendChild(item);
collectionHolder.dataset.index++;
$(".presta-products-family-delete").off("click", deletePrestataireProductFamily);
$(".presta-products-family-delete").on("click", deletePrestataireProductFamily);
$('.prestataire-product-families-select').off('change', onPrestataireProductFamilyChange);
$('.prestataire-product-families-select').on('change', onPrestataireProductFamilyChange);
};
$("#add-prestataire-products-family").on("click", addFormToCollection);
});
......@@ -331,6 +331,14 @@ sonata_admin:
icon: '<i class="fa fa-upload"></i>'
items:
- admin.import
sonata.admin.productsFamily:
keep_open: false
on_top: true
label: "Familles de produits"
label_catalogue: SonataAdminBundle
icon: '<i class="fa fa-shopping-basket"></i>'
items:
- admin.productsFamily
sonata.admin.group.globalparameter:
keep_open: false
on_top: true
......
......@@ -14,6 +14,8 @@ parameters:
sonata.media.admin.gallery.class: 'App\Admin\GalleryAdmin'
tav_env: '%env(TAV_ENV)%'
presta_self_init_and_eval: '%env(PRESTA_SELF_INIT_AND_EVAL)%'
automatisation_reconversion: '%env(AUTOMATISATION_RECONVERSION)%'
presta_extra_data: '%env(PRESTA_EXTRA_DATA)%'
# PARAMETRES DES IMPORTS POSSIBLE POUR L'APPLICATION DE GESTION DE MONNAIE LOCALE COMPLEMENTAIRE
app.import.separator: ';'
......@@ -658,6 +660,16 @@ services:
show_mosaic_button: false
public: true
admin.productsFamily:
class: App\Admin\ProductFamilyAdmin
arguments: [~, App\Entity\ProductFamily, ~]
tags:
- name: sonata.admin
manager_type: orm
group: "Familles de Produits"
label: "Familles de Produits"
public: true
sonata.media.provider.csv:
class: App\Admin\ImportProvider
tags:
......
......@@ -3359,9 +3359,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001491",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001491.tgz",
"integrity": "sha512-17EYIi4TLnPiTzVKMveIxU5ETlxbSO3B6iPvMbprqnKh4qJsQGk5Nh1Lp4jIMAE0XfrujsJuWZAM3oJdMHaKBA==",
"version": "1.0.30001589",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001589.tgz",
"integrity": "sha512-vNQWS6kI+q6sBlHbh71IIeC+sRwK2N3EDySc/updIGhIee2x5z00J4c1242/5/d6EpEMdOnk/m+6tuk4/tcsqg==",
"dev": true,
"funding": [
{
......@@ -12880,9 +12880,9 @@
}
},
"caniuse-lite": {
"version": "1.0.30001491",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001491.tgz",
"integrity": "sha512-17EYIi4TLnPiTzVKMveIxU5ETlxbSO3B6iPvMbprqnKh4qJsQGk5Nh1Lp4jIMAE0XfrujsJuWZAM3oJdMHaKBA==",
"version": "1.0.30001589",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001589.tgz",
"integrity": "sha512-vNQWS6kI+q6sBlHbh71IIeC+sRwK2N3EDySc/updIGhIee2x5z00J4c1242/5/d6EpEMdOnk/m+6tuk4/tcsqg==",
"dev": true
},
"chalk": {
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -3,16 +3,16 @@
"app": {
"js": [
"/build/runtime.6ad5c9da.js",
"/build/app.9cc97810.js"
"/build/app.94b71822.js"
],
"css": [
"/build/app.20b881c9.css"
"/build/app.c40ef51c.css"
]
},
"admin": {
"js": [
"/build/runtime.6ad5c9da.js",
"/build/admin.cee4d78d.js"
"/build/admin.86a2d986.js"
],
"css": [
"/build/admin.5dc0eea7.css"
......
{
"build/app.css": "/build/app.20b881c9.css",
"build/app.js": "/build/app.9cc97810.js",
"build/app.css": "/build/app.c40ef51c.css",
"build/app.js": "/build/app.94b71822.js",
"build/admin.css": "/build/admin.5dc0eea7.css",
"build/admin.js": "/build/admin.cee4d78d.js",
"build/admin.js": "/build/admin.86a2d986.js",
"build/runtime.js": "/build/runtime.6ad5c9da.js",
"build/images/fa-solid-900.svg": "/build/images/fa-solid-900.a838c42a.svg",
"build/images/fa-brands-400.svg": "/build/images/fa-brands-400.05d20183.svg",
......
(()=>{"use strict";var e={913:()=>{try{self["workbox:core:6.5.1"]&&_()}catch(e){}},977:()=>{try{self["workbox:precaching:6.5.1"]&&_()}catch(e){}},80:()=>{try{self["workbox:routing:6.5.1"]&&_()}catch(e){}},873:()=>{try{self["workbox:strategies:6.5.1"]&&_()}catch(e){}}},t={};function s(a){var n=t[a];if(void 0!==n)return n.exports;var r=t[a]={exports:{}};return e[a](r,r.exports,s),r.exports}(()=>{s(913);const e=(e,...t)=>{let s=e;return t.length>0&&(s+=` :: ${JSON.stringify(t)}`),s};class t extends Error{constructor(t,s){super(e(t,s)),this.name=t,this.details=s}}const a={googleAnalytics:"googleAnalytics",precache:"precache-v2",prefix:"workbox",runtime:"runtime",suffix:"undefined"!=typeof registration?registration.scope:""},n=e=>[a.prefix,e,a.suffix].filter((e=>e&&e.length>0)).join("-"),r=e=>e||n(a.precache),i=e=>e||n(a.runtime);function c(e,t){const s=t();return e.waitUntil(s),s}s(977);function o(e){if(!e)throw new t("add-to-cache-list-unexpected-type",{entry:e});if("string"==typeof e){const t=new URL(e,location.href);return{cacheKey:t.href,url:t.href}}const{revision:s,url:a}=e;if(!a)throw new t("add-to-cache-list-unexpected-type",{entry:e});if(!s){const e=new URL(a,location.href);return{cacheKey:e.href,url:e.href}}const n=new URL(a,location.href),r=new URL(a,location.href);return n.searchParams.set("__WB_REVISION__",s),{cacheKey:n.href,url:r.href}}class h{constructor(){this.updatedURLs=[],this.notUpdatedURLs=[],this.handlerWillStart=async({request:e,state:t})=>{t&&(t.originalRequest=e)},this.cachedResponseWillBeUsed=async({event:e,state:t,cachedResponse:s})=>{if("install"===e.type&&t&&t.originalRequest&&t.originalRequest instanceof Request){const e=t.originalRequest.url;s?this.notUpdatedURLs.push(e):this.updatedURLs.push(e)}return s}}}class l{constructor({precacheController:e}){this.cacheKeyWillBeUsed=async({request:e,params:t})=>{const s=(null==t?void 0:t.cacheKey)||this._precacheController.getCacheKeyForURL(e.url);return s?new Request(s,{headers:e.headers}):e},this._precacheController=e}}let u;async function f(e,s){let a=null;if(e.url){a=new URL(e.url).origin}if(a!==self.location.origin)throw new t("cross-origin-copy-response",{origin:a});const n=e.clone(),r={headers:new Headers(n.headers),status:n.status,statusText:n.statusText},i=s?s(r):r,c=function(){if(void 0===u){const e=new Response("");if("body"in e)try{new Response(e.body),u=!0}catch(e){u=!1}u=!1}return u}()?n.body:await n.blob();return new Response(c,i)}function d(e,t){const s=new URL(e);for(const e of t)s.searchParams.delete(e);return s.href}class p{constructor(){this.promise=new Promise(((e,t)=>{this.resolve=e,this.reject=t}))}}const g=new Set;s(873);function y(e){return"string"==typeof e?new Request(e):e}class w{constructor(e,t){this._cacheKeys={},Object.assign(this,t),this.event=t.event,this._strategy=e,this._handlerDeferred=new p,this._extendLifetimePromises=[],this._plugins=[...e.plugins],this._pluginStateMap=new Map;for(const e of this._plugins)this._pluginStateMap.set(e,{});this.event.waitUntil(this._handlerDeferred.promise)}async fetch(e){const{event:s}=this;let a=y(e);if("navigate"===a.mode&&s instanceof FetchEvent&&s.preloadResponse){const e=await s.preloadResponse;if(e)return e}const n=this.hasCallback("fetchDidFail")?a.clone():null;try{for(const e of this.iterateCallbacks("requestWillFetch"))a=await e({request:a.clone(),event:s})}catch(e){if(e instanceof Error)throw new t("plugin-error-request-will-fetch",{thrownErrorMessage:e.message})}const r=a.clone();try{let e;e=await fetch(a,"navigate"===a.mode?void 0:this._strategy.fetchOptions);for(const t of this.iterateCallbacks("fetchDidSucceed"))e=await t({event:s,request:r,response:e});return e}catch(e){throw n&&await this.runCallbacks("fetchDidFail",{error:e,event:s,originalRequest:n.clone(),request:r.clone()}),e}}async fetchAndCachePut(e){const t=await this.fetch(e),s=t.clone();return this.waitUntil(this.cachePut(e,s)),t}async cacheMatch(e){const t=y(e);let s;const{cacheName:a,matchOptions:n}=this._strategy,r=await this.getCacheKey(t,"read"),i=Object.assign(Object.assign({},n),{cacheName:a});s=await caches.match(r,i);for(const e of this.iterateCallbacks("cachedResponseWillBeUsed"))s=await e({cacheName:a,matchOptions:n,cachedResponse:s,request:r,event:this.event})||void 0;return s}async cachePut(e,s){const a=y(e);var n;await(n=0,new Promise((e=>setTimeout(e,n))));const r=await this.getCacheKey(a,"write");if(!s)throw new t("cache-put-with-no-response",{url:(i=r.url,new URL(String(i),location.href).href.replace(new RegExp(`^${location.origin}`),""))});var i;const c=await this._ensureResponseSafeToCache(s);if(!c)return!1;const{cacheName:o,matchOptions:h}=this._strategy,l=await self.caches.open(o),u=this.hasCallback("cacheDidUpdate"),f=u?await async function(e,t,s,a){const n=d(t.url,s);if(t.url===n)return e.match(t,a);const r=Object.assign(Object.assign({},a),{ignoreSearch:!0}),i=await e.keys(t,r);for(const t of i)if(n===d(t.url,s))return e.match(t,a)}(l,r.clone(),["__WB_REVISION__"],h):null;try{await l.put(r,u?c.clone():c)}catch(e){if(e instanceof Error)throw"QuotaExceededError"===e.name&&await async function(){for(const e of g)await e()}(),e}for(const e of this.iterateCallbacks("cacheDidUpdate"))await e({cacheName:o,oldResponse:f,newResponse:c.clone(),request:r,event:this.event});return!0}async getCacheKey(e,t){const s=`${e.url} | ${t}`;if(!this._cacheKeys[s]){let a=e;for(const e of this.iterateCallbacks("cacheKeyWillBeUsed"))a=y(await e({mode:t,request:a,event:this.event,params:this.params}));this._cacheKeys[s]=a}return this._cacheKeys[s]}hasCallback(e){for(const t of this._strategy.plugins)if(e in t)return!0;return!1}async runCallbacks(e,t){for(const s of this.iterateCallbacks(e))await s(t)}*iterateCallbacks(e){for(const t of this._strategy.plugins)if("function"==typeof t[e]){const s=this._pluginStateMap.get(t),a=a=>{const n=Object.assign(Object.assign({},a),{state:s});return t[e](n)};yield a}}waitUntil(e){return this._extendLifetimePromises.push(e),e}async doneWaiting(){let e;for(;e=this._extendLifetimePromises.shift();)await e}destroy(){this._handlerDeferred.resolve(null)}async _ensureResponseSafeToCache(e){let t=e,s=!1;for(const e of this.iterateCallbacks("cacheWillUpdate"))if(t=await e({request:this.request,response:t,event:this.event})||void 0,s=!0,!t)break;return s||t&&200!==t.status&&(t=void 0),t}}class m extends class{constructor(e={}){this.cacheName=i(e.cacheName),this.plugins=e.plugins||[],this.fetchOptions=e.fetchOptions,this.matchOptions=e.matchOptions}handle(e){const[t]=this.handleAll(e);return t}handleAll(e){e instanceof FetchEvent&&(e={event:e,request:e.request});const t=e.event,s="string"==typeof e.request?new Request(e.request):e.request,a="params"in e?e.params:void 0,n=new w(this,{event:t,request:s,params:a}),r=this._getResponse(n,s,t);return[r,this._awaitComplete(r,n,s,t)]}async _getResponse(e,s,a){let n;await e.runCallbacks("handlerWillStart",{event:a,request:s});try{if(n=await this._handle(s,e),!n||"error"===n.type)throw new t("no-response",{url:s.url})}catch(t){if(t instanceof Error)for(const r of e.iterateCallbacks("handlerDidError"))if(n=await r({error:t,event:a,request:s}),n)break;if(!n)throw t}for(const t of e.iterateCallbacks("handlerWillRespond"))n=await t({event:a,request:s,response:n});return n}async _awaitComplete(e,t,s,a){let n,r;try{n=await e}catch(r){}try{await t.runCallbacks("handlerDidRespond",{event:a,request:s,response:n}),await t.doneWaiting()}catch(e){e instanceof Error&&(r=e)}if(await t.runCallbacks("handlerDidComplete",{event:a,request:s,response:n,error:r}),t.destroy(),r)throw r}}{constructor(e={}){e.cacheName=r(e.cacheName),super(e),this._fallbackToNetwork=!1!==e.fallbackToNetwork,this.plugins.push(m.copyRedirectedCacheableResponsesPlugin)}async _handle(e,t){const s=await t.cacheMatch(e);return s||(t.event&&"install"===t.event.type?await this._handleInstall(e,t):await this._handleFetch(e,t))}async _handleFetch(e,s){let a;const n=s.params||{};if(!this._fallbackToNetwork)throw new t("missing-precache-entry",{cacheName:this.cacheName,url:e.url});{0;const t=n.integrity,r=e.integrity,i=!r||r===t;if(a=await s.fetch(new Request(e,{integrity:r||t})),t&&i){this._useDefaultCacheabilityPluginIfNeeded();await s.cachePut(e,a.clone());0}}return a}async _handleInstall(e,s){this._useDefaultCacheabilityPluginIfNeeded();const a=await s.fetch(e);if(!await s.cachePut(e,a.clone()))throw new t("bad-precaching-response",{url:e.url,status:a.status});return a}_useDefaultCacheabilityPluginIfNeeded(){let e=null,t=0;for(const[s,a]of this.plugins.entries())a!==m.copyRedirectedCacheableResponsesPlugin&&(a===m.defaultPrecacheCacheabilityPlugin&&(e=s),a.cacheWillUpdate&&t++);0===t?this.plugins.push(m.defaultPrecacheCacheabilityPlugin):t>1&&null!==e&&this.plugins.splice(e,1)}}m.defaultPrecacheCacheabilityPlugin={cacheWillUpdate:async({response:e})=>!e||e.status>=400?null:e},m.copyRedirectedCacheableResponsesPlugin={cacheWillUpdate:async({response:e})=>e.redirected?await f(e):e};class _{constructor({cacheName:e,plugins:t=[],fallbackToNetwork:s=!0}={}){this._urlsToCacheKeys=new Map,this._urlsToCacheModes=new Map,this._cacheKeysToIntegrities=new Map,this._strategy=new m({cacheName:r(e),plugins:[...t,new l({precacheController:this})],fallbackToNetwork:s}),this.install=this.install.bind(this),this.activate=this.activate.bind(this)}get strategy(){return this._strategy}precache(e){this.addToCacheList(e),this._installAndActiveListenersAdded||(self.addEventListener("install",this.install),self.addEventListener("activate",this.activate),this._installAndActiveListenersAdded=!0)}addToCacheList(e){const s=[];for(const a of e){"string"==typeof a?s.push(a):a&&void 0===a.revision&&s.push(a.url);const{cacheKey:e,url:n}=o(a),r="string"!=typeof a&&a.revision?"reload":"default";if(this._urlsToCacheKeys.has(n)&&this._urlsToCacheKeys.get(n)!==e)throw new t("add-to-cache-list-conflicting-entries",{firstEntry:this._urlsToCacheKeys.get(n),secondEntry:e});if("string"!=typeof a&&a.integrity){if(this._cacheKeysToIntegrities.has(e)&&this._cacheKeysToIntegrities.get(e)!==a.integrity)throw new t("add-to-cache-list-conflicting-integrities",{url:n});this._cacheKeysToIntegrities.set(e,a.integrity)}if(this._urlsToCacheKeys.set(n,e),this._urlsToCacheModes.set(n,r),s.length>0){const e=`Workbox is precaching URLs without revision info: ${s.join(", ")}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;console.warn(e)}}}install(e){return c(e,(async()=>{const t=new h;this.strategy.plugins.push(t);for(const[t,s]of this._urlsToCacheKeys){const a=this._cacheKeysToIntegrities.get(s),n=this._urlsToCacheModes.get(t),r=new Request(t,{integrity:a,cache:n,credentials:"same-origin"});await Promise.all(this.strategy.handleAll({params:{cacheKey:s},request:r,event:e}))}const{updatedURLs:s,notUpdatedURLs:a}=t;return{updatedURLs:s,notUpdatedURLs:a}}))}activate(e){return c(e,(async()=>{const e=await self.caches.open(this.strategy.cacheName),t=await e.keys(),s=new Set(this._urlsToCacheKeys.values()),a=[];for(const n of t)s.has(n.url)||(await e.delete(n),a.push(n.url));return{deletedURLs:a}}))}getURLsToCacheKeys(){return this._urlsToCacheKeys}getCachedURLs(){return[...this._urlsToCacheKeys.keys()]}getCacheKeyForURL(e){const t=new URL(e,location.href);return this._urlsToCacheKeys.get(t.href)}getIntegrityForCacheKey(e){return this._cacheKeysToIntegrities.get(e)}async matchPrecache(e){const t=e instanceof Request?e.url:e,s=this.getCacheKeyForURL(t);if(s){return(await self.caches.open(this.strategy.cacheName)).match(s)}}createHandlerBoundToURL(e){const s=this.getCacheKeyForURL(e);if(!s)throw new t("non-precached-url",{url:e});return t=>(t.request=new Request(e),t.params=Object.assign({cacheKey:s},t.params),this.strategy.handle(t))}}let R;const v=()=>(R||(R=new _),R);s(80);const C=e=>e&&"object"==typeof e?e:{handle:e};class b{constructor(e,t,s="GET"){this.handler=C(t),this.match=e,this.method=s}setCatchHandler(e){this.catchHandler=C(e)}}class q extends b{constructor(e,t,s){super((({url:t})=>{const s=e.exec(t.href);if(s&&(t.origin===location.origin||0===s.index))return s.slice(1)}),t,s)}}class U{constructor(){this._routes=new Map,this._defaultHandlerMap=new Map}get routes(){return this._routes}addFetchListener(){self.addEventListener("fetch",(e=>{const{request:t}=e,s=this.handleRequest({request:t,event:e});s&&e.respondWith(s)}))}addCacheListener(){self.addEventListener("message",(e=>{if(e.data&&"CACHE_URLS"===e.data.type){const{payload:t}=e.data;0;const s=Promise.all(t.urlsToCache.map((t=>{"string"==typeof t&&(t=[t]);const s=new Request(...t);return this.handleRequest({request:s,event:e})})));e.waitUntil(s),e.ports&&e.ports[0]&&s.then((()=>e.ports[0].postMessage(!0)))}}))}handleRequest({request:e,event:t}){const s=new URL(e.url,location.href);if(!s.protocol.startsWith("http"))return void 0;const a=s.origin===location.origin,{params:n,route:r}=this.findMatchingRoute({event:t,request:e,sameOrigin:a,url:s});let i=r&&r.handler;const c=e.method;if(!i&&this._defaultHandlerMap.has(c)&&(i=this._defaultHandlerMap.get(c)),!i)return void 0;let o;try{o=i.handle({url:s,request:e,event:t,params:n})}catch(e){o=Promise.reject(e)}const h=r&&r.catchHandler;return o instanceof Promise&&(this._catchHandler||h)&&(o=o.catch((async a=>{if(h){0;try{return await h.handle({url:s,request:e,event:t,params:n})}catch(e){e instanceof Error&&(a=e)}}if(this._catchHandler)return this._catchHandler.handle({url:s,request:e,event:t});throw a}))),o}findMatchingRoute({url:e,sameOrigin:t,request:s,event:a}){const n=this._routes.get(s.method)||[];for(const r of n){let n;const i=r.match({url:e,sameOrigin:t,request:s,event:a});if(i)return n=i,(Array.isArray(n)&&0===n.length||i.constructor===Object&&0===Object.keys(i).length||"boolean"==typeof i)&&(n=void 0),{route:r,params:n}}return{}}setDefaultHandler(e,t="GET"){this._defaultHandlerMap.set(t,C(e))}setCatchHandler(e){this._catchHandler=C(e)}registerRoute(e){this._routes.has(e.method)||this._routes.set(e.method,[]),this._routes.get(e.method).push(e)}unregisterRoute(e){if(!this._routes.has(e.method))throw new t("unregister-route-but-not-found-with-method",{method:e.method});const s=this._routes.get(e.method).indexOf(e);if(!(s>-1))throw new t("unregister-route-route-not-registered");this._routes.get(e.method).splice(s,1)}}let L;class k extends b{constructor(e,t){super((({request:s})=>{const a=e.getURLsToCacheKeys();for(const n of function*(e,{ignoreURLParametersMatching:t=[/^utm_/,/^fbclid$/],directoryIndex:s="index.html",cleanURLs:a=!0,urlManipulation:n}={}){const r=new URL(e,location.href);r.hash="",yield r.href;const i=function(e,t=[]){for(const s of[...e.searchParams.keys()])t.some((e=>e.test(s)))&&e.searchParams.delete(s);return e}(r,t);if(yield i.href,s&&i.pathname.endsWith("/")){const e=new URL(i.href);e.pathname+=s,yield e.href}if(a){const e=new URL(i.href);e.pathname+=".html",yield e.href}if(n){const e=n({url:r});for(const t of e)yield t.href}}(s.url,t)){const t=a.get(n);if(t){return{cacheKey:t,integrity:e.getIntegrityForCacheKey(t)}}}}),e.strategy)}}function K(e){const s=v();!function(e,s,a){let n;if("string"==typeof e){const t=new URL(e,location.href);n=new b((({url:e})=>e.href===t.href),s,a)}else if(e instanceof RegExp)n=new q(e,s,a);else if("function"==typeof e)n=new b(e,s,a);else{if(!(e instanceof b))throw new t("unsupported-route-type",{moduleName:"workbox-routing",funcName:"registerRoute",paramName:"capture"});n=e}(L||(L=new U,L.addFetchListener(),L.addCacheListener()),L).registerRoute(n)}(new k(s,e))}var T;(function(e){v().precache(e)})([{'revision':null,'url':'/build/admin.5dc0eea7.css'},{'revision':null,'url':'/build/admin.cee4d78d.js'},{'revision':'ad79405d542b397996a3079203114b42','url':'/build/admin.cee4d78d.js.LICENSE.txt'},{'revision':null,'url':'/build/app.20b881c9.css'},{'revision':null,'url':'/build/app.9cc97810.js'},{'revision':'4ff7361e3c3e359ae88c5fae5738746d','url':'/build/app.9cc97810.js.LICENSE.txt'},{'revision':null,'url':'/build/fonts/fa-brands-400.3dc44d22.woff2'},{'revision':null,'url':'/build/fonts/fa-regular-400.3dc6ca01.woff2'},{'revision':null,'url':'/build/fonts/fa-solid-900.496d5fc1.woff2'},{'revision':null,'url':'/build/fonts/source-sans-pro-v14-latin-300.d2c7d5c5.woff2'},{'revision':null,'url':'/build/fonts/source-sans-pro-v14-latin-600.17c0392c.woff2'},{'revision':null,'url':'/build/fonts/source-sans-pro-v14-latin-600italic.cc34c6e7.woff2'},{'revision':null,'url':'/build/fonts/source-sans-pro-v14-latin-700.ed37bc60.woff2'},{'revision':null,'url':'/build/fonts/source-sans-pro-v14-latin-900.476756cd.woff2'},{'revision':null,'url':'/build/fonts/source-sans-pro-v14-latin-italic.a07cb9c5.woff2'},{'revision':null,'url':'/build/fonts/source-sans-pro-v14-latin-regular.f74389bd.woff2'},{'revision':null,'url':'/build/images/fa-brands-400.05d20183.svg'},{'revision':null,'url':'/build/images/fa-regular-400.9a0810d6.svg'},{'revision':null,'url':'/build/images/fa-solid-900.a838c42a.svg'},{'revision':null,'url':'/build/images/source-sans-pro-v14-latin-300.4e7fe004.svg'},{'revision':null,'url':'/build/images/source-sans-pro-v14-latin-600.cf2758ae.svg'},{'revision':null,'url':'/build/images/source-sans-pro-v14-latin-600italic.7249d863.svg'},{'revision':null,'url':'/build/images/source-sans-pro-v14-latin-700.3e4b9e19.svg'},{'revision':null,'url':'/build/images/source-sans-pro-v14-latin-900.060d8c51.svg'},{'revision':null,'url':'/build/images/source-sans-pro-v14-latin-italic.08dc9b1c.svg'},{'revision':null,'url':'/build/images/source-sans-pro-v14-latin-regular.3bb9538c.svg'},{'revision':null,'url':'/build/runtime.6ad5c9da.js'}]),K(T),self.addEventListener("fetch",(function(e){e.respondWith(caches.match(e.request).then((function(t){return t||fetch(e.request)})).catch((function(){return caches.match("/offline.html")})))}))})()})();
\ No newline at end of file
(()=>{"use strict";var e={913:()=>{try{self["workbox:core:6.5.1"]&&_()}catch(e){}},977:()=>{try{self["workbox:precaching:6.5.1"]&&_()}catch(e){}},80:()=>{try{self["workbox:routing:6.5.1"]&&_()}catch(e){}},873:()=>{try{self["workbox:strategies:6.5.1"]&&_()}catch(e){}}},t={};function s(a){var n=t[a];if(void 0!==n)return n.exports;var r=t[a]={exports:{}};return e[a](r,r.exports,s),r.exports}(()=>{s(913);const e=(e,...t)=>{let s=e;return t.length>0&&(s+=` :: ${JSON.stringify(t)}`),s};class t extends Error{constructor(t,s){super(e(t,s)),this.name=t,this.details=s}}const a={googleAnalytics:"googleAnalytics",precache:"precache-v2",prefix:"workbox",runtime:"runtime",suffix:"undefined"!=typeof registration?registration.scope:""},n=e=>[a.prefix,e,a.suffix].filter((e=>e&&e.length>0)).join("-"),r=e=>e||n(a.precache),i=e=>e||n(a.runtime);function c(e,t){const s=t();return e.waitUntil(s),s}s(977);function o(e){if(!e)throw new t("add-to-cache-list-unexpected-type",{entry:e});if("string"==typeof e){const t=new URL(e,location.href);return{cacheKey:t.href,url:t.href}}const{revision:s,url:a}=e;if(!a)throw new t("add-to-cache-list-unexpected-type",{entry:e});if(!s){const e=new URL(a,location.href);return{cacheKey:e.href,url:e.href}}const n=new URL(a,location.href),r=new URL(a,location.href);return n.searchParams.set("__WB_REVISION__",s),{cacheKey:n.href,url:r.href}}class h{constructor(){this.updatedURLs=[],this.notUpdatedURLs=[],this.handlerWillStart=async({request:e,state:t})=>{t&&(t.originalRequest=e)},this.cachedResponseWillBeUsed=async({event:e,state:t,cachedResponse:s})=>{if("install"===e.type&&t&&t.originalRequest&&t.originalRequest instanceof Request){const e=t.originalRequest.url;s?this.notUpdatedURLs.push(e):this.updatedURLs.push(e)}return s}}}class l{constructor({precacheController:e}){this.cacheKeyWillBeUsed=async({request:e,params:t})=>{const s=(null==t?void 0:t.cacheKey)||this._precacheController.getCacheKeyForURL(e.url);return s?new Request(s,{headers:e.headers}):e},this._precacheController=e}}let u;async function f(e,s){let a=null;if(e.url){a=new URL(e.url).origin}if(a!==self.location.origin)throw new t("cross-origin-copy-response",{origin:a});const n=e.clone(),r={headers:new Headers(n.headers),status:n.status,statusText:n.statusText},i=s?s(r):r,c=function(){if(void 0===u){const e=new Response("");if("body"in e)try{new Response(e.body),u=!0}catch(e){u=!1}u=!1}return u}()?n.body:await n.blob();return new Response(c,i)}function d(e,t){const s=new URL(e);for(const e of t)s.searchParams.delete(e);return s.href}class p{constructor(){this.promise=new Promise(((e,t)=>{this.resolve=e,this.reject=t}))}}const g=new Set;s(873);function y(e){return"string"==typeof e?new Request(e):e}class w{constructor(e,t){this._cacheKeys={},Object.assign(this,t),this.event=t.event,this._strategy=e,this._handlerDeferred=new p,this._extendLifetimePromises=[],this._plugins=[...e.plugins],this._pluginStateMap=new Map;for(const e of this._plugins)this._pluginStateMap.set(e,{});this.event.waitUntil(this._handlerDeferred.promise)}async fetch(e){const{event:s}=this;let a=y(e);if("navigate"===a.mode&&s instanceof FetchEvent&&s.preloadResponse){const e=await s.preloadResponse;if(e)return e}const n=this.hasCallback("fetchDidFail")?a.clone():null;try{for(const e of this.iterateCallbacks("requestWillFetch"))a=await e({request:a.clone(),event:s})}catch(e){if(e instanceof Error)throw new t("plugin-error-request-will-fetch",{thrownErrorMessage:e.message})}const r=a.clone();try{let e;e=await fetch(a,"navigate"===a.mode?void 0:this._strategy.fetchOptions);for(const t of this.iterateCallbacks("fetchDidSucceed"))e=await t({event:s,request:r,response:e});return e}catch(e){throw n&&await this.runCallbacks("fetchDidFail",{error:e,event:s,originalRequest:n.clone(),request:r.clone()}),e}}async fetchAndCachePut(e){const t=await this.fetch(e),s=t.clone();return this.waitUntil(this.cachePut(e,s)),t}async cacheMatch(e){const t=y(e);let s;const{cacheName:a,matchOptions:n}=this._strategy,r=await this.getCacheKey(t,"read"),i=Object.assign(Object.assign({},n),{cacheName:a});s=await caches.match(r,i);for(const e of this.iterateCallbacks("cachedResponseWillBeUsed"))s=await e({cacheName:a,matchOptions:n,cachedResponse:s,request:r,event:this.event})||void 0;return s}async cachePut(e,s){const a=y(e);var n;await(n=0,new Promise((e=>setTimeout(e,n))));const r=await this.getCacheKey(a,"write");if(!s)throw new t("cache-put-with-no-response",{url:(i=r.url,new URL(String(i),location.href).href.replace(new RegExp(`^${location.origin}`),""))});var i;const c=await this._ensureResponseSafeToCache(s);if(!c)return!1;const{cacheName:o,matchOptions:h}=this._strategy,l=await self.caches.open(o),u=this.hasCallback("cacheDidUpdate"),f=u?await async function(e,t,s,a){const n=d(t.url,s);if(t.url===n)return e.match(t,a);const r=Object.assign(Object.assign({},a),{ignoreSearch:!0}),i=await e.keys(t,r);for(const t of i)if(n===d(t.url,s))return e.match(t,a)}(l,r.clone(),["__WB_REVISION__"],h):null;try{await l.put(r,u?c.clone():c)}catch(e){if(e instanceof Error)throw"QuotaExceededError"===e.name&&await async function(){for(const e of g)await e()}(),e}for(const e of this.iterateCallbacks("cacheDidUpdate"))await e({cacheName:o,oldResponse:f,newResponse:c.clone(),request:r,event:this.event});return!0}async getCacheKey(e,t){const s=`${e.url} | ${t}`;if(!this._cacheKeys[s]){let a=e;for(const e of this.iterateCallbacks("cacheKeyWillBeUsed"))a=y(await e({mode:t,request:a,event:this.event,params:this.params}));this._cacheKeys[s]=a}return this._cacheKeys[s]}hasCallback(e){for(const t of this._strategy.plugins)if(e in t)return!0;return!1}async runCallbacks(e,t){for(const s of this.iterateCallbacks(e))await s(t)}*iterateCallbacks(e){for(const t of this._strategy.plugins)if("function"==typeof t[e]){const s=this._pluginStateMap.get(t),a=a=>{const n=Object.assign(Object.assign({},a),{state:s});return t[e](n)};yield a}}waitUntil(e){return this._extendLifetimePromises.push(e),e}async doneWaiting(){let e;for(;e=this._extendLifetimePromises.shift();)await e}destroy(){this._handlerDeferred.resolve(null)}async _ensureResponseSafeToCache(e){let t=e,s=!1;for(const e of this.iterateCallbacks("cacheWillUpdate"))if(t=await e({request:this.request,response:t,event:this.event})||void 0,s=!0,!t)break;return s||t&&200!==t.status&&(t=void 0),t}}class m extends class{constructor(e={}){this.cacheName=i(e.cacheName),this.plugins=e.plugins||[],this.fetchOptions=e.fetchOptions,this.matchOptions=e.matchOptions}handle(e){const[t]=this.handleAll(e);return t}handleAll(e){e instanceof FetchEvent&&(e={event:e,request:e.request});const t=e.event,s="string"==typeof e.request?new Request(e.request):e.request,a="params"in e?e.params:void 0,n=new w(this,{event:t,request:s,params:a}),r=this._getResponse(n,s,t);return[r,this._awaitComplete(r,n,s,t)]}async _getResponse(e,s,a){let n;await e.runCallbacks("handlerWillStart",{event:a,request:s});try{if(n=await this._handle(s,e),!n||"error"===n.type)throw new t("no-response",{url:s.url})}catch(t){if(t instanceof Error)for(const r of e.iterateCallbacks("handlerDidError"))if(n=await r({error:t,event:a,request:s}),n)break;if(!n)throw t}for(const t of e.iterateCallbacks("handlerWillRespond"))n=await t({event:a,request:s,response:n});return n}async _awaitComplete(e,t,s,a){let n,r;try{n=await e}catch(r){}try{await t.runCallbacks("handlerDidRespond",{event:a,request:s,response:n}),await t.doneWaiting()}catch(e){e instanceof Error&&(r=e)}if(await t.runCallbacks("handlerDidComplete",{event:a,request:s,response:n,error:r}),t.destroy(),r)throw r}}{constructor(e={}){e.cacheName=r(e.cacheName),super(e),this._fallbackToNetwork=!1!==e.fallbackToNetwork,this.plugins.push(m.copyRedirectedCacheableResponsesPlugin)}async _handle(e,t){const s=await t.cacheMatch(e);return s||(t.event&&"install"===t.event.type?await this._handleInstall(e,t):await this._handleFetch(e,t))}async _handleFetch(e,s){let a;const n=s.params||{};if(!this._fallbackToNetwork)throw new t("missing-precache-entry",{cacheName:this.cacheName,url:e.url});{0;const t=n.integrity,r=e.integrity,i=!r||r===t;if(a=await s.fetch(new Request(e,{integrity:r||t})),t&&i){this._useDefaultCacheabilityPluginIfNeeded();await s.cachePut(e,a.clone());0}}return a}async _handleInstall(e,s){this._useDefaultCacheabilityPluginIfNeeded();const a=await s.fetch(e);if(!await s.cachePut(e,a.clone()))throw new t("bad-precaching-response",{url:e.url,status:a.status});return a}_useDefaultCacheabilityPluginIfNeeded(){let e=null,t=0;for(const[s,a]of this.plugins.entries())a!==m.copyRedirectedCacheableResponsesPlugin&&(a===m.defaultPrecacheCacheabilityPlugin&&(e=s),a.cacheWillUpdate&&t++);0===t?this.plugins.push(m.defaultPrecacheCacheabilityPlugin):t>1&&null!==e&&this.plugins.splice(e,1)}}m.defaultPrecacheCacheabilityPlugin={cacheWillUpdate:async({response:e})=>!e||e.status>=400?null:e},m.copyRedirectedCacheableResponsesPlugin={cacheWillUpdate:async({response:e})=>e.redirected?await f(e):e};class _{constructor({cacheName:e,plugins:t=[],fallbackToNetwork:s=!0}={}){this._urlsToCacheKeys=new Map,this._urlsToCacheModes=new Map,this._cacheKeysToIntegrities=new Map,this._strategy=new m({cacheName:r(e),plugins:[...t,new l({precacheController:this})],fallbackToNetwork:s}),this.install=this.install.bind(this),this.activate=this.activate.bind(this)}get strategy(){return this._strategy}precache(e){this.addToCacheList(e),this._installAndActiveListenersAdded||(self.addEventListener("install",this.install),self.addEventListener("activate",this.activate),this._installAndActiveListenersAdded=!0)}addToCacheList(e){const s=[];for(const a of e){"string"==typeof a?s.push(a):a&&void 0===a.revision&&s.push(a.url);const{cacheKey:e,url:n}=o(a),r="string"!=typeof a&&a.revision?"reload":"default";if(this._urlsToCacheKeys.has(n)&&this._urlsToCacheKeys.get(n)!==e)throw new t("add-to-cache-list-conflicting-entries",{firstEntry:this._urlsToCacheKeys.get(n),secondEntry:e});if("string"!=typeof a&&a.integrity){if(this._cacheKeysToIntegrities.has(e)&&this._cacheKeysToIntegrities.get(e)!==a.integrity)throw new t("add-to-cache-list-conflicting-integrities",{url:n});this._cacheKeysToIntegrities.set(e,a.integrity)}if(this._urlsToCacheKeys.set(n,e),this._urlsToCacheModes.set(n,r),s.length>0){const e=`Workbox is precaching URLs without revision info: ${s.join(", ")}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;console.warn(e)}}}install(e){return c(e,(async()=>{const t=new h;this.strategy.plugins.push(t);for(const[t,s]of this._urlsToCacheKeys){const a=this._cacheKeysToIntegrities.get(s),n=this._urlsToCacheModes.get(t),r=new Request(t,{integrity:a,cache:n,credentials:"same-origin"});await Promise.all(this.strategy.handleAll({params:{cacheKey:s},request:r,event:e}))}const{updatedURLs:s,notUpdatedURLs:a}=t;return{updatedURLs:s,notUpdatedURLs:a}}))}activate(e){return c(e,(async()=>{const e=await self.caches.open(this.strategy.cacheName),t=await e.keys(),s=new Set(this._urlsToCacheKeys.values()),a=[];for(const n of t)s.has(n.url)||(await e.delete(n),a.push(n.url));return{deletedURLs:a}}))}getURLsToCacheKeys(){return this._urlsToCacheKeys}getCachedURLs(){return[...this._urlsToCacheKeys.keys()]}getCacheKeyForURL(e){const t=new URL(e,location.href);return this._urlsToCacheKeys.get(t.href)}getIntegrityForCacheKey(e){return this._cacheKeysToIntegrities.get(e)}async matchPrecache(e){const t=e instanceof Request?e.url:e,s=this.getCacheKeyForURL(t);if(s){return(await self.caches.open(this.strategy.cacheName)).match(s)}}createHandlerBoundToURL(e){const s=this.getCacheKeyForURL(e);if(!s)throw new t("non-precached-url",{url:e});return t=>(t.request=new Request(e),t.params=Object.assign({cacheKey:s},t.params),this.strategy.handle(t))}}let R;const v=()=>(R||(R=new _),R);s(80);const C=e=>e&&"object"==typeof e?e:{handle:e};class b{constructor(e,t,s="GET"){this.handler=C(t),this.match=e,this.method=s}setCatchHandler(e){this.catchHandler=C(e)}}class q extends b{constructor(e,t,s){super((({url:t})=>{const s=e.exec(t.href);if(s&&(t.origin===location.origin||0===s.index))return s.slice(1)}),t,s)}}class U{constructor(){this._routes=new Map,this._defaultHandlerMap=new Map}get routes(){return this._routes}addFetchListener(){self.addEventListener("fetch",(e=>{const{request:t}=e,s=this.handleRequest({request:t,event:e});s&&e.respondWith(s)}))}addCacheListener(){self.addEventListener("message",(e=>{if(e.data&&"CACHE_URLS"===e.data.type){const{payload:t}=e.data;0;const s=Promise.all(t.urlsToCache.map((t=>{"string"==typeof t&&(t=[t]);const s=new Request(...t);return this.handleRequest({request:s,event:e})})));e.waitUntil(s),e.ports&&e.ports[0]&&s.then((()=>e.ports[0].postMessage(!0)))}}))}handleRequest({request:e,event:t}){const s=new URL(e.url,location.href);if(!s.protocol.startsWith("http"))return void 0;const a=s.origin===location.origin,{params:n,route:r}=this.findMatchingRoute({event:t,request:e,sameOrigin:a,url:s});let i=r&&r.handler;const c=e.method;if(!i&&this._defaultHandlerMap.has(c)&&(i=this._defaultHandlerMap.get(c)),!i)return void 0;let o;try{o=i.handle({url:s,request:e,event:t,params:n})}catch(e){o=Promise.reject(e)}const h=r&&r.catchHandler;return o instanceof Promise&&(this._catchHandler||h)&&(o=o.catch((async a=>{if(h){0;try{return await h.handle({url:s,request:e,event:t,params:n})}catch(e){e instanceof Error&&(a=e)}}if(this._catchHandler)return this._catchHandler.handle({url:s,request:e,event:t});throw a}))),o}findMatchingRoute({url:e,sameOrigin:t,request:s,event:a}){const n=this._routes.get(s.method)||[];for(const r of n){let n;const i=r.match({url:e,sameOrigin:t,request:s,event:a});if(i)return n=i,(Array.isArray(n)&&0===n.length||i.constructor===Object&&0===Object.keys(i).length||"boolean"==typeof i)&&(n=void 0),{route:r,params:n}}return{}}setDefaultHandler(e,t="GET"){this._defaultHandlerMap.set(t,C(e))}setCatchHandler(e){this._catchHandler=C(e)}registerRoute(e){this._routes.has(e.method)||this._routes.set(e.method,[]),this._routes.get(e.method).push(e)}unregisterRoute(e){if(!this._routes.has(e.method))throw new t("unregister-route-but-not-found-with-method",{method:e.method});const s=this._routes.get(e.method).indexOf(e);if(!(s>-1))throw new t("unregister-route-route-not-registered");this._routes.get(e.method).splice(s,1)}}let L;class k extends b{constructor(e,t){super((({request:s})=>{const a=e.getURLsToCacheKeys();for(const n of function*(e,{ignoreURLParametersMatching:t=[/^utm_/,/^fbclid$/],directoryIndex:s="index.html",cleanURLs:a=!0,urlManipulation:n}={}){const r=new URL(e,location.href);r.hash="",yield r.href;const i=function(e,t=[]){for(const s of[...e.searchParams.keys()])t.some((e=>e.test(s)))&&e.searchParams.delete(s);return e}(r,t);if(yield i.href,s&&i.pathname.endsWith("/")){const e=new URL(i.href);e.pathname+=s,yield e.href}if(a){const e=new URL(i.href);e.pathname+=".html",yield e.href}if(n){const e=n({url:r});for(const t of e)yield t.href}}(s.url,t)){const t=a.get(n);if(t){return{cacheKey:t,integrity:e.getIntegrityForCacheKey(t)}}}}),e.strategy)}}function K(e){const s=v();!function(e,s,a){let n;if("string"==typeof e){const t=new URL(e,location.href);n=new b((({url:e})=>e.href===t.href),s,a)}else if(e instanceof RegExp)n=new q(e,s,a);else if("function"==typeof e)n=new b(e,s,a);else{if(!(e instanceof b))throw new t("unsupported-route-type",{moduleName:"workbox-routing",funcName:"registerRoute",paramName:"capture"});n=e}(L||(L=new U,L.addFetchListener(),L.addCacheListener()),L).registerRoute(n)}(new k(s,e))}var T;(function(e){v().precache(e)})([{'revision':null,'url':'/build/admin.5dc0eea7.css'},{'revision':null,'url':'/build/admin.86a2d986.js'},{'revision':'ad79405d542b397996a3079203114b42','url':'/build/admin.86a2d986.js.LICENSE.txt'},{'revision':null,'url':'/build/app.94b71822.js'},{'revision':'4ff7361e3c3e359ae88c5fae5738746d','url':'/build/app.94b71822.js.LICENSE.txt'},{'revision':null,'url':'/build/app.c40ef51c.css'},{'revision':null,'url':'/build/fonts/fa-brands-400.3dc44d22.woff2'},{'revision':null,'url':'/build/fonts/fa-regular-400.3dc6ca01.woff2'},{'revision':null,'url':'/build/fonts/fa-solid-900.496d5fc1.woff2'},{'revision':null,'url':'/build/fonts/source-sans-pro-v14-latin-300.d2c7d5c5.woff2'},{'revision':null,'url':'/build/fonts/source-sans-pro-v14-latin-600.17c0392c.woff2'},{'revision':null,'url':'/build/fonts/source-sans-pro-v14-latin-600italic.cc34c6e7.woff2'},{'revision':null,'url':'/build/fonts/source-sans-pro-v14-latin-700.ed37bc60.woff2'},{'revision':null,'url':'/build/fonts/source-sans-pro-v14-latin-900.476756cd.woff2'},{'revision':null,'url':'/build/fonts/source-sans-pro-v14-latin-italic.a07cb9c5.woff2'},{'revision':null,'url':'/build/fonts/source-sans-pro-v14-latin-regular.f74389bd.woff2'},{'revision':null,'url':'/build/images/fa-brands-400.05d20183.svg'},{'revision':null,'url':'/build/images/fa-regular-400.9a0810d6.svg'},{'revision':null,'url':'/build/images/fa-solid-900.a838c42a.svg'},{'revision':null,'url':'/build/images/source-sans-pro-v14-latin-300.4e7fe004.svg'},{'revision':null,'url':'/build/images/source-sans-pro-v14-latin-600.cf2758ae.svg'},{'revision':null,'url':'/build/images/source-sans-pro-v14-latin-600italic.7249d863.svg'},{'revision':null,'url':'/build/images/source-sans-pro-v14-latin-700.3e4b9e19.svg'},{'revision':null,'url':'/build/images/source-sans-pro-v14-latin-900.060d8c51.svg'},{'revision':null,'url':'/build/images/source-sans-pro-v14-latin-italic.08dc9b1c.svg'},{'revision':null,'url':'/build/images/source-sans-pro-v14-latin-regular.3bb9538c.svg'},{'revision':null,'url':'/build/runtime.6ad5c9da.js'}]),K(T),self.addEventListener("fetch",(function(e){e.respondWith(caches.match(e.request).then((function(t){return t||fetch(e.request)})).catch((function(){return caches.match("/offline.html")})))}))})()})();
\ No newline at end of file
<?php
namespace App\Admin;
use Sonata\AdminBundle\Admin\AbstractAdmin;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Show\ShowMapper;
use Symfony\Component\Form\Extension\Core\Type\TextType;
/**
* Administration des familles de produits.
*
* KOHINOS : Outil de gestion de Monnaie Locale Complémentaire
*/
class ProductFamilyAdmin extends AbstractAdmin
{
protected function configureFormFields(FormMapper $form): void
{
$form->add('name', TextType::class, [
'label' => 'Nom'
]);
}
protected function configureDatagridFilters(DatagridMapper $datagrid): void
{
$datagrid->add('name', null, [
'label' => 'Nom'
]);
}
protected function configureListFields(ListMapper $list): void
{
$list->addIdentifier('name', null, [
'label' => 'Nom'
]);
}
}
\ No newline at end of file
......@@ -74,6 +74,7 @@ class FluxController extends AbstractController
protected $operationUtils;
protected $tokenGenerator;
protected $validator;
protected $userManager;
public function __construct(
Security $security,
......@@ -86,7 +87,8 @@ class FluxController extends AbstractController
TAVCotisationUtils $tavCotisationsUtils,
TokenGeneratorInterface $tokenGenerator,
ValidatorInterface $validator,
CsrfTokenManagerInterface $tokenManager
CsrfTokenManagerInterface $tokenManager,
UserManagerInterface $userManager
) {
$this->security = $security;
$this->em = $em;
......@@ -99,6 +101,7 @@ class FluxController extends AbstractController
$this->validator = $validator;
$this->tokenManager = $tokenManager;
$this->tavCotisationsUtils = $tavCotisationsUtils;
$this->userManager = $userManager;
}
protected function manageFluxForm(Request $request, Form $form, $template = '@kohinos/flux/transaction.html.twig', $params = [])
......
......@@ -49,6 +49,8 @@ class UserPrestataireController extends FluxController
}
$this->em->persist($adresse);
}
// caissiers validations
if (!empty($form->get('newcaissiers')->getData())) {
$caissiers = explode(';', $form->get('newcaissiers')->getData());
$errors = [];
......@@ -102,6 +104,17 @@ class UserPrestataireController extends FluxController
} elseif (!$request->isXmlHttpRequest()) {
return new Response('', Response::HTTP_BAD_REQUEST);
}
} else {
foreach ($form->getErrors(true, true) as $error) {
// Add flash error message in case of error with the embedded form
if (str_contains($error->getCause()->getPropertyPath(), 'productFamily')) {
$this->addFlash(
'error',
$error->getMessage()
);
break;
}
}
}
return $this->redirectToRoute('index');
......
......@@ -9,6 +9,7 @@ use App\Entity\EntityTrait\HasEcompteEntity;
use App\Flux\AccountableInterface;
use App\Flux\AccountableObject;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Gedmo\Timestampable\Traits\TimestampableEntity;
......@@ -325,6 +326,15 @@ class Prestataire extends AccountableObject implements AccountableInterface
protected $tauxreconversion;
/**
* Fréquence de reconversion en cas d'automatisation des reconversions.
*
* @var string
* @ORM\Column(name="reconversionFrequency", type="string", length=50, nullable=true)
* @Groups({"read", "write"})
*/
protected $reconversionFrequency;
/**
* @var ArrayCollection|AccountPrestataire[]
* @ORM\OneToMany(targetEntity="AccountPrestataire", mappedBy="prestataire")
*/
......@@ -343,6 +353,11 @@ class Prestataire extends AccountableObject implements AccountableInterface
private $lastTransactionsExportDatetime;
/**
* @ORM\OneToMany(targetEntity=PrestataireProductFamily::class, mappedBy="prestataire", orphanRemoval=true, cascade={"persist"})
*/
private $prestataireProductFamilies;
/**
* @var float
*
* @ORM\Column(name="conventionnement", type="decimal", scale=2, nullable=true)
......@@ -361,6 +376,7 @@ class Prestataire extends AccountableObject implements AccountableInterface
$this->rubriques = new ArrayCollection();
$this->contacts = new ArrayCollection();
$this->accounts = new ArrayCollection();
$this->prestataireProductFamilies = new ArrayCollection();
}
public function getId()
......@@ -1116,6 +1132,28 @@ class Prestataire extends AccountableObject implements AccountableInterface
}
/**
* Get reconversionFrequency.
*
* @return
*/
public function getReconversionFrequency(): ?string
{
return $this->reconversionFrequency;
}
/**
* Set reconversionFrequency.
*
* @return $this
*/
public function setReconversionFrequency(?string $reconversionFrequency): self
{
$this->reconversionFrequency = $reconversionFrequency;
return $this;
}
/**
* Get comments.
*
* @return string comments
......@@ -1165,6 +1203,36 @@ class Prestataire extends AccountableObject implements AccountableInterface
}
/**
* @return Collection<int, PrestataireProductFamily>
*/
public function getPrestataireProductFamilies(): Collection
{
return $this->prestataireProductFamilies;
}
public function addPrestataireProductFamily(PrestataireProductFamily $prestataireProductFamily): self
{
if (!$this->prestataireProductFamilies->contains($prestataireProductFamily)) {
$this->prestataireProductFamilies[] = $prestataireProductFamily;
$prestataireProductFamily->setPrestataire($this);
}
return $this;
}
public function removePrestataireProductFamily(PrestataireProductFamily $prestataireProductFamily): self
{
if ($this->prestataireProductFamilies->removeElement($prestataireProductFamily)) {
// set the owning side to null (unless already changed)
if ($prestataireProductFamily->getPrestataire() === $this) {
$prestataireProductFamily->setPrestataire(null);
}
}
return $this;
}
/**
* @return mixed
*/
public function getConventionnement()
......
<?php
namespace App\Entity;
use App\Repository\PrestataireProductFamilyRepository;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* @ORM\Entity(repositoryClass=PrestataireProductFamilyRepository::class)
* @ORM\Table(name="prestataire_product_family", uniqueConstraints={@ORM\UniqueConstraint(name="prestataireproductfamily", columns={"prestataire_id", "product_family_id"})}) )
* @UniqueEntity(
* fields={"prestataire", "productFamily"},
* errorPath="productFamily",
* message="Famille de produits déjà renseignée, les modifications n'ont pas été enregistrées."
* )
*/
class PrestataireProductFamily
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity=Prestataire::class, inversedBy="prestataireProductFamilies")
* @ORM\JoinColumn(nullable=false)
*/
private $prestataire;
/**
* @ORM\ManyToOne(targetEntity=ProductFamily::class)
* @ORM\JoinColumn(nullable=false)
*/
private $productFamily;
/**
* Products list as a string. Not related to any kind of product entity.
*
* @ORM\Column(type="text")
*/
private $products;
public function getId(): ?int
{
return $this->id;
}
public function getPrestataire(): ?Prestataire
{
return $this->prestataire;
}
public function setPrestataire(?Prestataire $prestataire): self
{
$this->prestataire = $prestataire;
return $this;
}
public function getProductFamily(): ?ProductFamily
{
return $this->productFamily;
}
public function setProductFamily(?ProductFamily $productFamily): self
{
$this->productFamily = $productFamily;
return $this;
}
public function getProducts(): ?string
{
return $this->products;
}
public function setProducts(string $products): self
{
$this->products = $products;
return $this;
}
}
<?php
namespace App\Entity;
use App\Repository\ProductFamilyRepository;
use Doctrine\ORM\Mapping as ORM;
use Ramsey\Uuid\Doctrine\UuidGenerator;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* @ORM\Entity(repositoryClass=ProductFamilyRepository::class)
* @UniqueEntity(fields="name", message="Une famille de produits portant ce nom existe déjà.")
*/
class ProductFamily
{
/**
* @var \Ramsey\Uuid\UuidInterface
*
* @ORM\Id
* @ORM\Column(type="uuid", unique=true)
* @ORM\GeneratedValue(strategy="CUSTOM")
* @ORM\CustomIdGenerator(class=UuidGenerator::class)
*/
private $id;
/**
* @ORM\Column(type="string", length=100, unique=true)
*/
private $name;
public function getId()
{
return $this->id;
}
/**
* Get name.
*
* @return string name
*/
public function getName(): ?string
{
return $this->name;
}
/**
* Set name.
*
* @return $this
*/
public function setName(string $name): self
{
$this->name = $name;
return $this;
}
}
<?php
namespace App\Enum;
abstract class ReconversionFrequencyEnum
{
const MOYEN_ONCE_A_MONTH = 'once_a_month';
const MOYEN_TWICE_A_MONTH = 'twice_a_month';
const MOYEN_ONCE_TWO_MONTHS = 'once_every_two_month';
/** @var array user friendly named type */
protected static $typeName = [
self::MOYEN_ONCE_A_MONTH => '1 fois par mois',
self::MOYEN_TWICE_A_MONTH => '2 fois par mois',
self::MOYEN_ONCE_TWO_MONTHS => '1 fois tous les deux mois',
];
/**
* @param string $typeShortName
*
* @return string
*/
public static function getTypeName($typeShortName)
{
if (!isset(static::$typeName[$typeShortName])) {
return "Unknown type ($typeShortName)";
}
return static::$typeName[$typeShortName];
}
/**
* @return array<string>
*/
public static function getAvailableTypes()
{
return [
self::MOYEN_ONCE_A_MONTH,
self::MOYEN_TWICE_A_MONTH,
self::MOYEN_ONCE_TWO_MONTHS,
];
}
}
......@@ -51,7 +51,7 @@ class DistributorSelfEvalPrestaQuizType extends SelfEvalPrestaQuizType
$this->opts['label'] = "Transparence et juste rémunération : " . $this->labelEvalGlob;
$this->opts['choices'] = $this->stdGlobalChoices;
$builder->add('transpar_global', ChoiceType::class, $this->opts);
$builder->add('transpar_global_comment', TextareaType::class, $this->cmtOpts);
$builder->add('transpar_global_comment', TextareaType::class, $this->globalCmtOpts);
/* PARTIE 4 : PRATIQUES AGRICOLES DURABLES */
$this->opts['label'] = "Détenez-vous des labels ou des certifications (AB, Bio, Nature et Progrès, système de garantie
......@@ -75,7 +75,7 @@ class DistributorSelfEvalPrestaQuizType extends SelfEvalPrestaQuizType
$this->opts['label'] = "Pratiques agricoles durables : " . $this->labelEvalGlob;
$this->opts['choices'] = $this->stdGlobalChoices;
$builder->add('disagdur_global', ChoiceType::class, $this->opts);
$builder->add('disagdur_global_comment', TextareaType::class, $this->cmtOpts);
$builder->add('disagdur_global_comment', TextareaType::class, $this->globalCmtOpts);
/* PARTIE 5 : LOCALITE DES PRODUITS */
$this->opts['label'] = "Quelle est la provenance de l'offre alimentaire globale en produits bruts ?";
......@@ -97,7 +97,7 @@ class DistributorSelfEvalPrestaQuizType extends SelfEvalPrestaQuizType
$this->opts['label'] = "Localité des produits : " . $this->labelEvalGlob;
$this->opts['choices'] = $this->stdGlobalChoices;
$builder->add('localite_global', ChoiceType::class, $this->opts);
$builder->add('localite_global_comment', TextareaType::class, $this->cmtOpts);
$builder->add('localite_global_comment', TextareaType::class, $this->globalCmtOpts);
//Review
if($options['mode'] !== self::PRESTA_EDIT) {
......
......@@ -4,7 +4,10 @@ namespace App\Form\Type;
use App\Application\Sonata\MediaBundle\Entity\Media;
use App\Entity\Prestataire;
use App\Entity\PrestataireProductFamily;
use App\Form\Type\PrestataireProductFamilyFormType;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use FOS\CKEditorBundle\Form\Type\CKEditorType;
use Sonata\MediaBundle\Form\Type\MediaType;
use Symfony\Component\Form\AbstractType;
......@@ -13,16 +16,20 @@ use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\UrlType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use App\Enum\ReconversionFrequencyEnum;
class PrestataireInfosFormType extends AbstractType
{
protected $em;
protected $container;
public function __construct(EntityManagerInterface $em)
public function __construct(EntityManagerInterface $em, ContainerInterface $container)
{
$this->em = $em;
$this->container = $container;
}
public function buildForm(FormBuilderInterface $builder, array $options)
......@@ -77,7 +84,40 @@ class PrestataireInfosFormType extends AbstractType
->add('web', UrlType::class, [
'label' => 'Site web :',
'required' => false,
])
]);
if ($this->container->getParameter('tav_env') && $this->container->getParameter('automatisation_reconversion')) {
$builder
->add('reconversionFrequency', ChoiceType::class, [
'choices' => ReconversionFrequencyEnum::getAvailableTypes(),
'choice_label' => function ($choice) {
return ReconversionFrequencyEnum::getTypeName($choice);
},
'expanded' => false,
'multiple' => false,
'label' => 'Fréquence de reconversion :',
'placeholder' => 'Choisir une option',
'required' => false,
]);
}
if ($this->container->getParameter('tav_env') && $this->container->getParameter('presta_extra_data')) {
$builder
->add('prestataireProductFamilies', CollectionType::class, [
'entry_type' => PrestataireProductFamilyFormType::class,
'required' => true,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'constraints' => new \Symfony\Component\Validator\Constraints\Valid(),
'label' => "Produits vendus, regroupés par famille ",
'error_mapping' => [
'productFamily' => 'prestataireProductFamilies',
],
]);
}
$builder
->add('description', CKEditorType::class, [
'label' => 'Description :',
'required' => false,
......
<?php
namespace App\Form\Type;
use App\Entity\PrestataireProductFamily;
use App\Entity\ProductFamily;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
class PrestataireProductFamilyFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('productFamily', EntityType::class, array(
'class' => ProductFamily::class,
'choice_label' => 'name',
'label' => 'Famille de produits ',
'required' => true,
'placeholder' => 'Choisissez une famille',
'attr' => ['class' => 'prestataire-product-families-select']
))
->add('products', TextType::class, [
'label' => 'Produits ',
'required' => true,
'attr' => ['class' => 'prestataire-product-families-products']
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => PrestataireProductFamily::class,
]);
}
public function getBlockPrefix()
{
return 'formPrestataireProductFamily';
}
}
......@@ -56,7 +56,7 @@ class ProducerSelfEvalPrestaQuizType extends SelfEvalPrestaQuizType
$this->opts['label'] = "Pratiques agricoles durables : " . $this->labelEvalGlob . " (cochez vert si vous détenez un label ou une certification)";
$this->opts['choices'] = $this->stdGlobalChoices;
$builder->add('proagdur_global', ChoiceType::class, $this->opts);
$builder->add('proagdur_global_comment', TextareaType::class, $this->cmtOpts);
$builder->add('proagdur_global_comment', TextareaType::class, $this->globalCmtOpts);
//Review
if($options['mode'] !== self::PRESTA_EDIT) {
......
......@@ -30,6 +30,7 @@ class SelfEvalPrestaQuizType extends AbstractType
protected array $opts;
protected array $reviewOpts;
protected array $cmtOpts;
protected array $globalCmtOpts;
protected array $reviewCmtOpts;
protected string $labelEvalGlob;
protected string $reviewLabel;
......@@ -79,10 +80,15 @@ class SelfEvalPrestaQuizType extends AbstractType
'required' => false,
'disabled' => $options['mode'] === self::READONLY
];
$this->cmtOpts = $this->reviewCmtOpts;
$this->cmtOpts['disabled'] = $options['mode'] !== self::PRESTA_EDIT;
$this->cmtOpts['attr']['placeholder'] = $options['mode'] !== self::PRESTA_EDIT ? '' : 'Commentaires';
$this->globalCmtOpts = $this->cmtOpts;
$this->globalCmtOpts['required'] = true;
$this->globalCmtOpts['attr']['placeholder'] = $options['mode'] !== self::PRESTA_EDIT ? '' : 'Commentaires (obligatoire)';
/* PARTIE 1 : ACCESSIBILITE ET INCLUSIVITE */
$this->opts['label'] = "Géographique et physique : le lieu est-il accessible par différents modes de transport ?";
$this->opts['choices'] = [
......@@ -116,7 +122,7 @@ class SelfEvalPrestaQuizType extends AbstractType
$this->opts['label'] = "Accessibilité et inclusivité : " . $this->labelEvalGlob;
$this->opts['choices'] = $this->stdGlobalChoices;
$builder->add('accessib_global', ChoiceType::class, $this->opts);
$builder->add('accessib_global_comment', TextareaType::class, $this->cmtOpts);
$builder->add('accessib_global_comment', TextareaType::class, $this->globalCmtOpts);
/* PARTIE 2 : BIEN-ETRE AU TRAVAIL */
$this->opts['label'] = "Le lieu met-il en place des actions pour faciliter l'accueil, l'intégration et la formation des personnes qui y travaillent ?";
......@@ -138,7 +144,7 @@ class SelfEvalPrestaQuizType extends AbstractType
$this->opts['label'] = "Bien-être au travail : " . $this->labelEvalGlob;
$this->opts['choices'] = $this->stdGlobalChoices;
$builder->add('bienetre_global', ChoiceType::class, $this->opts);
$builder->add('bienetre_global_comment', TextareaType::class, $this->cmtOpts);
$builder->add('bienetre_global_comment', TextareaType::class, $this->globalCmtOpts);
//Review
if($options['mode'] !== self::PRESTA_EDIT) {
......
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20240216095500 extends AbstractMigration
{
public function getDescription() : string
{
return '';
}
public function up(Schema $schema) : void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE prestataire ADD reconversionFrequency VARCHAR(50) DEFAULT NULL, CHANGE iban iban LONGTEXT DEFAULT NULL COMMENT \'(DC2Type:personal_data)\'');
}
public function down(Schema $schema) : void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE prestataire DROP reconversionFrequency, CHANGE iban iban LONGTEXT CHARACTER SET utf8mb3 DEFAULT NULL COLLATE `utf8mb3_general_ci` COMMENT \'(DC2Type:personal_data)\'');
}
}
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20240216140320 extends AbstractMigration
{
public function getDescription() : string
{
return '';
}
public function up(Schema $schema) : void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE product_family (id CHAR(36) NOT NULL COMMENT \'(DC2Type:uuid)\', name VARCHAR(100) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_general_ci` ENGINE = InnoDB');
$this->addSql('ALTER TABLE prestataire CHANGE iban iban LONGTEXT DEFAULT NULL COMMENT \'(DC2Type:personal_data)\'');
}
public function down(Schema $schema) : void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('DROP TABLE product_family');
$this->addSql('ALTER TABLE prestataire CHANGE iban iban LONGTEXT CHARACTER SET utf8mb3 DEFAULT NULL COLLATE `utf8mb3_general_ci` COMMENT \'(DC2Type:personal_data)\'');
}
}
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20240219140409 extends AbstractMigration
{
public function getDescription() : string
{
return '';
}
public function up(Schema $schema) : void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE prestataire CHANGE iban iban LONGTEXT DEFAULT NULL COMMENT \'(DC2Type:personal_data)\'');
$this->addSql('CREATE UNIQUE INDEX UNIQ_C79A60FF5E237E06 ON product_family (name)');
}
public function down(Schema $schema) : void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE prestataire CHANGE iban iban LONGTEXT CHARACTER SET utf8mb3 DEFAULT NULL COLLATE `utf8mb3_general_ci` COMMENT \'(DC2Type:personal_data)\'');
$this->addSql('DROP INDEX UNIQ_C79A60FF5E237E06 ON product_family');
}
}
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20240220101222 extends AbstractMigration
{
public function getDescription() : string
{
return '';
}
public function up(Schema $schema) : void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE prestataire_product_family (id INT AUTO_INCREMENT NOT NULL, prestataire_id CHAR(36) NOT NULL COMMENT \'(DC2Type:uuid)\', product_family_id CHAR(36) NOT NULL COMMENT \'(DC2Type:uuid)\', products LONGTEXT NOT NULL, INDEX IDX_9B0F7A58BE3DB2B7 (prestataire_id), INDEX IDX_9B0F7A58ADFEE0E7 (product_family_id), UNIQUE INDEX prestataireproductfamily (prestataire_id, product_family_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_general_ci` ENGINE = InnoDB');
$this->addSql('ALTER TABLE prestataire_product_family ADD CONSTRAINT FK_9B0F7A58BE3DB2B7 FOREIGN KEY (prestataire_id) REFERENCES prestataire (id)');
$this->addSql('ALTER TABLE prestataire_product_family ADD CONSTRAINT FK_9B0F7A58ADFEE0E7 FOREIGN KEY (product_family_id) REFERENCES product_family (id)');
$this->addSql('ALTER TABLE prestataire CHANGE iban iban LONGTEXT DEFAULT NULL COMMENT \'(DC2Type:personal_data)\'');
}
public function down(Schema $schema) : void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('DROP TABLE prestataire_product_family');
$this->addSql('ALTER TABLE prestataire CHANGE iban iban LONGTEXT CHARACTER SET utf8mb3 DEFAULT NULL COLLATE `utf8mb3_general_ci` COMMENT \'(DC2Type:personal_data)\'');
}
}
<?php
namespace App\Repository;
use App\Entity\PrestataireProductFamily;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\OptimisticLockException;
use Doctrine\ORM\ORMException;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<PrestataireProductFamily>
*
* @method PrestataireProductFamily|null find($id, $lockMode = null, $lockVersion = null)
* @method PrestataireProductFamily|null findOneBy(array $criteria, array $orderBy = null)
* @method PrestataireProductFamily[] findAll()
* @method PrestataireProductFamily[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class PrestataireProductFamilyRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, PrestataireProductFamily::class);
}
/**
* @throws ORMException
* @throws OptimisticLockException
*/
public function add(PrestataireProductFamily $entity, bool $flush = true): void
{
$this->_em->persist($entity);
if ($flush) {
$this->_em->flush();
}
}
/**
* @throws ORMException
* @throws OptimisticLockException
*/
public function remove(PrestataireProductFamily $entity, bool $flush = true): void
{
$this->_em->remove($entity);
if ($flush) {
$this->_em->flush();
}
}
// /**
// * @return PrestataireProductFamily[] Returns an array of PrestataireProductFamily objects
// */
/*
public function findByExampleField($value)
{
return $this->createQueryBuilder('p')
->andWhere('p.exampleField = :val')
->setParameter('val', $value)
->orderBy('p.id', 'ASC')
->setMaxResults(10)
->getQuery()
->getResult()
;
}
*/
/*
public function findOneBySomeField($value): ?PrestataireProductFamily
{
return $this->createQueryBuilder('p')
->andWhere('p.exampleField = :val')
->setParameter('val', $value)
->getQuery()
->getOneOrNullResult()
;
}
*/
}
<?php
namespace App\Repository;
use App\Entity\ProductFamily;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\OptimisticLockException;
use Doctrine\ORM\ORMException;
use Doctrine\Persistence\ManagerRegistry;
/**
* @extends ServiceEntityRepository<ProductFamily>
*
* @method ProductFamily|null find($id, $lockMode = null, $lockVersion = null)
* @method ProductFamily|null findOneBy(array $criteria, array $orderBy = null)
* @method ProductFamily[] findAll()
* @method ProductFamily[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class ProductFamilyRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, ProductFamily::class);
}
/**
* @throws ORMException
* @throws OptimisticLockException
*/
public function add(ProductFamily $entity, bool $flush = true): void
{
$this->_em->persist($entity);
if ($flush) {
$this->_em->flush();
}
}
/**
* @throws ORMException
* @throws OptimisticLockException
*/
public function remove(ProductFamily $entity, bool $flush = true): void
{
$this->_em->remove($entity);
if ($flush) {
$this->_em->flush();
}
}
// /**
// * @return ProductFamily[] Returns an array of ProductFamily objects
// */
/*
public function findByExampleField($value)
{
return $this->createQueryBuilder('p')
->andWhere('p.exampleField = :val')
->setParameter('val', $value)
->orderBy('p.id', 'ASC')
->setMaxResults(10)
->getQuery()
->getResult()
;
}
*/
/*
public function findOneBySomeField($value): ?ProductFamily
{
return $this->createQueryBuilder('p')
->andWhere('p.exampleField = :val')
->setParameter('val', $value)
->getQuery()
->getOneOrNullResult()
;
}
*/
}
......@@ -5,8 +5,35 @@
{% endblock blocktitle %}
{% block blocksubtitle %}
{% endblock blocksubtitle %}
{% block blockcontent %}
{% set form = getPrestataireInfosForm(app.user) %}
{# Create "template" as a macro for a product family entry in the form collection #}
{% import _self as formMacros %}
{% macro printPrestataireProductFamilyForm(prestataireProductFamilyForm, formName = "") %}
<div class="presta-products-family">
<div class="presta-products-family-fields">
<div class="form-group presta-products-family-form-group">
{{ form_label(prestataireProductFamilyForm.productFamily) }}
{{ form_widget(prestataireProductFamilyForm.productFamily) }}
</div>
<div class="form-group presta-products-family-form-group">
{{ form_label(prestataireProductFamilyForm.products) }}
{{ form_widget(prestataireProductFamilyForm.products) }}
</div>
<div class="presta-products-family-duplicate-warning">{{'Cette famille de produits est déjà renseignée.'|trans}}</div>
</div>
<a href="#" class="presta-products-family-delete">
<i
class="fa fa-times delete-icon"
id="formPrestataireInfos_prestataireProductFamilies_{{ formName == '' ? '__name__' : formName }}_delete"
></i>
</a>
</div>
{% endmacro %}
{{form_start(form)}}
{{ form_row(form.raison) }}
{{ form_row(form.statut) }}
......@@ -24,6 +51,9 @@
{{ form_row(form.metier) }}
{{ form_row(form.horaires) }}
{{ form_row(form.web) }}
{% if form.reconversionFrequency is defined %}
{{ form_row(form.reconversionFrequency) }}
{% endif %}
<hr/>
{{ form_row(form.media) }}
{{ form_row(form.description) }}
......@@ -39,6 +69,31 @@
<hr/>
{{ form_row(form.newcaissiers) }}
<hr/>
{% if form.prestataireProductFamilies is defined %}
<h4>{{ form_label(form.prestataireProductFamilies) }}</h4>
{{ form_errors(form.prestataireProductFamilies) }}
<div
class="presta-products-families-list"
data-index="{{ form.prestataireProductFamilies|length > 0 ? form.prestataireProductFamilies|last.vars.name + 1 : 0 }}"
data-prototype="{{ formMacros.printPrestataireProductFamilyForm(form.prestataireProductFamilies.vars.prototype)|e('html_attr') }}"
>
{% for prestataireProductFamilyForm in form.prestataireProductFamilies %}
{{ formMacros.printPrestataireProductFamilyForm(prestataireProductFamilyForm, prestataireProductFamilyForm.vars.name) }}
{% endfor %}
{% do form.prestataireProductFamilies.setRendered() %}
</div>
<button
type="button"
id="add-prestataire-products-family"
class="btn-primary btn"
data-collection-holder-class="presta-products-families-list"
>
<i class="fa fa-plus"></i>
</button>
<hr/>
{% endif %}
{{ form_row(form.acceptemlc) }}
{{ form_row(form.save) }}
{{form_end(form)}}
......
......@@ -1852,9 +1852,9 @@ caniuse-api@^3.0.0:
lodash.uniq "^4.5.0"
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001489:
version "1.0.30001491"
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001491.tgz"
integrity sha512-17EYIi4TLnPiTzVKMveIxU5ETlxbSO3B6iPvMbprqnKh4qJsQGk5Nh1Lp4jIMAE0XfrujsJuWZAM3oJdMHaKBA==
version "1.0.30001589"
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001589.tgz"
integrity sha512-vNQWS6kI+q6sBlHbh71IIeC+sRwK2N3EDySc/updIGhIee2x5z00J4c1242/5/d6EpEMdOnk/m+6tuk4/tcsqg==
chalk@^2.0.0, chalk@^2.3.2, chalk@^2.4.2:
version "2.4.2"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment