```
✨ feat(Customer): Ajoute la fonction de clonage d'entité Customer. ✨ feat(SignClient): Utilise Docuseal avec PDF pour la signature des devis. ✨ feat(AvatarController): Ajoute un endpoint pour le verrouillage de l'application. ✨ feat(IpWall): Ajoute un composant web pour bloquer l'accès basé sur l'IP. 🎨 style(admin.scss): Ajoute des styles pour le modal de paiement et les murs de sécurité. ✨ feat(RegisterPayment): Ajoute un composant pour enregistrer les paiements. 🐛 fix(DevisPdf): Corrige l'alignement des totaux dans le PDF du devis. 🔥 chore: Ajoute discord_bot/node_modules au .gitignore. ✨ feat(ExportComptable): Ajoute une commande pour exporter les données comptables. ✨ feat(LockdownWall): Ajoute un composant web pour le verrouillage de l'application. 🐛 fix(CustomerController): Corrige la copie des contacts lors du clonage du client. ✨ feat(SecurityWall): Ajoute un composant web pour activer/désactiver le filtre de confidentialité.
This commit is contained in:
2
.env
2
.env
@@ -59,7 +59,7 @@ OVH_SECRET=12239d273975b5ab53318907fb66d355
|
||||
OVH_CUSTOMER=56c387eb9ca4b9a2de4d4d97fd3d7f22
|
||||
|
||||
DOCUSIGN_URL=https://signature.esy-web.dev/api
|
||||
DOCUSIGN_KEY=52u82oCoiG79awGsuxLfJqhxYjg8mrJfAsJJHejRMFa
|
||||
DOCUSIGN_KEY=pgAU116mCFmeF7WQSezHqxtZW8V1fgo31u5d2FXoaKe
|
||||
|
||||
STANCER_PRIVATE_KEY=stest_Rv4Hz8ae2wQdjnBVCays7wPo
|
||||
STANCER_PUBLIC_KEY=ptest_raV5vZ51Lnp2DfBtu5TVs5o0
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -35,3 +35,4 @@ coverage/
|
||||
script/demande/hosts.ini
|
||||
backup/*.zip
|
||||
backup/*.sql
|
||||
discord_bot/node_modules
|
||||
|
||||
@@ -6,6 +6,9 @@ import {AutoCustomer} from './class/AutoCustomer'
|
||||
import {RepeatLine} from './class/RepeatLine'
|
||||
import {RegisterPayment} from './class/RegisterPayment'
|
||||
import {OrderCtrl} from './class/OrderCtrl'
|
||||
import {LockdownWall} from './class/LockdownWall'
|
||||
import {SecurityWall} from './class/SecurityWall'
|
||||
import {IpWall} from './class/IpWall'
|
||||
import preactCustomElement from './functions/preact'
|
||||
|
||||
|
||||
@@ -14,8 +17,11 @@ function script() {
|
||||
customElements.define('server-card',ServerCard,{extends:'div'})
|
||||
customElements.define('auto-customer',AutoCustomer,{extends:'button'})
|
||||
customElements.define('repeat-line',RepeatLine,{extends:'div'})
|
||||
customElements.define('lockdown-wall',LockdownWall,{})
|
||||
customElements.define('security-wall',SecurityWall,{})
|
||||
customElements.define('ip-wall',IpWall,{})
|
||||
customElements.define('order-ctrl',OrderCtrl,{extends:'div'})
|
||||
customElements.define("register-payment",RegisterPayment,{extends:'a'})
|
||||
customElements.define("register-payment",RegisterPayment,{extends:'button'})
|
||||
}
|
||||
|
||||
function full() {
|
||||
|
||||
@@ -310,3 +310,103 @@ input {
|
||||
margin: 0.25rem;
|
||||
height: 90%;
|
||||
}
|
||||
|
||||
.modal-payment{
|
||||
z-index: 9000;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
background: rgba(0,0,0,0.5);
|
||||
backdrop-filter: blur(5px);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.modal-payment-content{
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
background: #1a202c;
|
||||
width: 50%;
|
||||
transform: translate(-50%,-50%);
|
||||
h2{
|
||||
text-align: center;
|
||||
font-size: 1.25rem;
|
||||
padding: 0.5rem;
|
||||
border-bottom: 1px solid #cdcdcd;
|
||||
}
|
||||
a {
|
||||
width: fit-content !important;
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
security-wall-item{
|
||||
background: black;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 5000;
|
||||
.content{
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%,-50%);
|
||||
span {
|
||||
text-align: center;
|
||||
display: block;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
h2 {
|
||||
font-size: 2rem;
|
||||
warn {
|
||||
color: red;
|
||||
font-weight: bolder;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
lockdown-wall-item{
|
||||
background: repeating-linear-gradient(
|
||||
45deg,
|
||||
black,
|
||||
black 20px,
|
||||
red 20px,
|
||||
red 40px
|
||||
);
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 5000;
|
||||
.content{
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background: rgba(0, 0, 0, 0.8); /* Fond noir semi-transparent */
|
||||
color: white; /* Texte blanc */
|
||||
padding: 2rem 3rem;
|
||||
border-radius: 10px;
|
||||
text-align: center;
|
||||
font-family: Arial, sans-serif;
|
||||
box-shadow: 0 0 15px rgba(255, 0, 0, 0.7); /* Ombre rouge pour souligner */
|
||||
span {
|
||||
text-align: center;
|
||||
display: block;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
h2 {
|
||||
font-size: 1.5rem;
|
||||
warn {
|
||||
color: red;
|
||||
font-weight: bolder;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
14
assets/class/IpWall.js
Normal file
14
assets/class/IpWall.js
Normal file
@@ -0,0 +1,14 @@
|
||||
export class IpWall extends HTMLElement {
|
||||
connectedCallback() {
|
||||
if (!document.querySelector('security-wall-item')) {
|
||||
let wall = document.createElement('security-wall-item');
|
||||
wall.innerHTML = `
|
||||
<div class="content">
|
||||
<h2><warn>/!\\ </warn> - Protection MAINFRAME - <warn>/!\\ </warn></h2>
|
||||
<span>Votre IP n'est pas autorisée par le système !</span>
|
||||
</div>
|
||||
`;
|
||||
document.body.appendChild(wall);
|
||||
}
|
||||
}
|
||||
}
|
||||
25
assets/class/LockdownWall.js
Normal file
25
assets/class/LockdownWall.js
Normal file
@@ -0,0 +1,25 @@
|
||||
export class LockdownWall extends HTMLElement {
|
||||
connectedCallback() {
|
||||
fetch("/artemis/lockdown")
|
||||
.then((r) => r.json())
|
||||
.then((result) => {
|
||||
if(result.lockdown) {
|
||||
if (!document.querySelector('lockdown-wall-item')) {
|
||||
let sound = new Audio("/sound/alert.mp3")
|
||||
let wall = document.createElement('lockdown-wall-item');
|
||||
wall.innerHTML = `
|
||||
<div class="content" style="padding: 20px; background: #ffcccc; color: #900; font-weight: bold; text-align: center; border: 2px solid #900; border-radius: 8px; max-width: 600px; margin: 30px auto; font-family: Arial, sans-serif;">
|
||||
<h2><warn>/!\\ </warn> - Protection MAINFRAME - <warn>/!\\ </warn></h2>
|
||||
<p>Verrouillage complet de l'application est en cours, aucune action n'est possible.</p>
|
||||
</div>
|
||||
`;
|
||||
document.body.appendChild(wall);
|
||||
|
||||
setInterval(() => {
|
||||
sound.play();
|
||||
}, 30000)
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
export class RegisterPayment extends HTMLAnchorElement {
|
||||
export class RegisterPayment extends HTMLButtonElement {
|
||||
connectedCallback() {
|
||||
let element = this;
|
||||
element.addEventListener('click', (event) => {
|
||||
@@ -9,9 +9,49 @@ export class RegisterPayment extends HTMLAnchorElement {
|
||||
modal.classList = "modal-payment"
|
||||
modal.innerHTML =`
|
||||
<div class="modal-payment-content">
|
||||
<h2>Enregistér un paiement</h2>
|
||||
<h2>Enregistrée un paiement</h2>
|
||||
<a class="block dbclose bg-red-600 hover:bg-red-700 text-white px-3 py-1 rounded">Fermer</a>
|
||||
<form method="post" class="content">
|
||||
<div class="flex space-x-4" is="order-ctrl">
|
||||
<fieldset class="form-group form-group--horizontal">
|
||||
<div class="flex space-x-4">
|
||||
<div class="flex-1">
|
||||
<div class="form-field">
|
||||
<div class="mb-1">
|
||||
<label for="titre" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Type</label>
|
||||
<select class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" required>
|
||||
<option value="CB">Carte Bancaire</option>
|
||||
<option value="PREV">Prévélevement</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="form-field">
|
||||
<div class="mb-1">
|
||||
<label for="titre" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Date</label>
|
||||
<input type="date" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" required />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="form-field">
|
||||
<div class="mb-1">
|
||||
<label for="titre" class="block mb-2 text-sm font-medium text-gray-900 dark:text-white">Montant</label>
|
||||
<input type="number" step="0.01" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500" required />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
`;
|
||||
modal.querySelector('.dbclose').addEventListener('click',()=>{
|
||||
modal.remove();
|
||||
})
|
||||
document.body.appendChild(modal);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
40
assets/class/SecurityWall.js
Normal file
40
assets/class/SecurityWall.js
Normal file
@@ -0,0 +1,40 @@
|
||||
export class SecurityWall extends HTMLElement {
|
||||
connectedCallback() {
|
||||
this.render();
|
||||
|
||||
// Ecoute globale pour Alt+P
|
||||
window.addEventListener('keydown', (event) => {
|
||||
if (event.altKey && event.key.toLowerCase() === 'p') {
|
||||
this.toggleWall();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const isEnabled = localStorage.getItem('mainframe-wallsecurity') === 'true';
|
||||
if (!isEnabled) {
|
||||
// Retirer si déjà présent
|
||||
const existing = document.querySelector('security-wall-item');
|
||||
if (existing) existing.remove();
|
||||
return;
|
||||
}
|
||||
|
||||
// Ajouter seulement si pas déjà présent
|
||||
if (!document.querySelector('security-wall-item')) {
|
||||
let wall = document.createElement('security-wall-item');
|
||||
wall.innerHTML = `
|
||||
<div class="content">
|
||||
<h2><warn>/!\\ </warn> - Protection MAINFRAME - <warn>/!\\ </warn></h2>
|
||||
<span>Filtre de confidentialité activée</span>
|
||||
</div>
|
||||
`;
|
||||
document.body.appendChild(wall);
|
||||
}
|
||||
}
|
||||
|
||||
toggleWall() {
|
||||
const current = localStorage.getItem('mainframe-wallsecurity') === 'true';
|
||||
localStorage.setItem('mainframe-wallsecurity', current ? 'false' : 'true');
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
34
discord_bot/.gitignore
vendored
Normal file
34
discord_bot/.gitignore
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
# dependencies (bun install)
|
||||
node_modules
|
||||
|
||||
# output
|
||||
out
|
||||
dist
|
||||
*.tgz
|
||||
|
||||
# code coverage
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# logs
|
||||
logs
|
||||
_.log
|
||||
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||
|
||||
# dotenv environment variable files
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# caches
|
||||
.eslintcache
|
||||
.cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# IntelliJ based IDEs
|
||||
.idea
|
||||
|
||||
# Finder (MacOS) folder config
|
||||
.DS_Store
|
||||
15
discord_bot/README.md
Normal file
15
discord_bot/README.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# discord_bot
|
||||
|
||||
To install dependencies:
|
||||
|
||||
```bash
|
||||
bun install
|
||||
```
|
||||
|
||||
To run:
|
||||
|
||||
```bash
|
||||
bun run index.ts
|
||||
```
|
||||
|
||||
This project was created using `bun init` in bun v1.2.22. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
|
||||
139
discord_bot/bun.lock
Normal file
139
discord_bot/bun.lock
Normal file
@@ -0,0 +1,139 @@
|
||||
{
|
||||
"lockfileVersion": 1,
|
||||
"workspaces": {
|
||||
"": {
|
||||
"name": "discord_bot",
|
||||
"dependencies": {
|
||||
"discord.js": "^14.22.1",
|
||||
"nodemon": "^3.1.10",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest",
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5",
|
||||
},
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@discordjs/builders": ["@discordjs/builders@1.11.3", "", { "dependencies": { "@discordjs/formatters": "^0.6.1", "@discordjs/util": "^1.1.1", "@sapphire/shapeshift": "^4.0.0", "discord-api-types": "^0.38.16", "fast-deep-equal": "^3.1.3", "ts-mixer": "^6.0.4", "tslib": "^2.6.3" } }, "sha512-p3kf5eV49CJiRTfhtutUCeivSyQ/l2JlKodW1ZquRwwvlOWmG9+6jFShX6x8rUiYhnP6wKI96rgN/SXMy5e5aw=="],
|
||||
|
||||
"@discordjs/collection": ["@discordjs/collection@1.5.3", "", {}, "sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ=="],
|
||||
|
||||
"@discordjs/formatters": ["@discordjs/formatters@0.6.1", "", { "dependencies": { "discord-api-types": "^0.38.1" } }, "sha512-5cnX+tASiPCqCWtFcFslxBVUaCetB0thvM/JyavhbXInP1HJIEU+Qv/zMrnuwSsX3yWH2lVXNJZeDK3EiP4HHg=="],
|
||||
|
||||
"@discordjs/rest": ["@discordjs/rest@2.6.0", "", { "dependencies": { "@discordjs/collection": "^2.1.1", "@discordjs/util": "^1.1.1", "@sapphire/async-queue": "^1.5.3", "@sapphire/snowflake": "^3.5.3", "@vladfrangu/async_event_emitter": "^2.4.6", "discord-api-types": "^0.38.16", "magic-bytes.js": "^1.10.0", "tslib": "^2.6.3", "undici": "6.21.3" } }, "sha512-RDYrhmpB7mTvmCKcpj+pc5k7POKszS4E2O9TYc+U+Y4iaCP+r910QdO43qmpOja8LRr1RJ0b3U+CqVsnPqzf4w=="],
|
||||
|
||||
"@discordjs/util": ["@discordjs/util@1.1.1", "", {}, "sha512-eddz6UnOBEB1oITPinyrB2Pttej49M9FZQY8NxgEvc3tq6ZICZ19m70RsmzRdDHk80O9NoYN/25AqJl8vPVf/g=="],
|
||||
|
||||
"@discordjs/ws": ["@discordjs/ws@1.2.3", "", { "dependencies": { "@discordjs/collection": "^2.1.0", "@discordjs/rest": "^2.5.1", "@discordjs/util": "^1.1.0", "@sapphire/async-queue": "^1.5.2", "@types/ws": "^8.5.10", "@vladfrangu/async_event_emitter": "^2.2.4", "discord-api-types": "^0.38.1", "tslib": "^2.6.2", "ws": "^8.17.0" } }, "sha512-wPlQDxEmlDg5IxhJPuxXr3Vy9AjYq5xCvFWGJyD7w7Np8ZGu+Mc+97LCoEc/+AYCo2IDpKioiH0/c/mj5ZR9Uw=="],
|
||||
|
||||
"@sapphire/async-queue": ["@sapphire/async-queue@1.5.5", "", {}, "sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg=="],
|
||||
|
||||
"@sapphire/shapeshift": ["@sapphire/shapeshift@4.0.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "lodash": "^4.17.21" } }, "sha512-d9dUmWVA7MMiKobL3VpLF8P2aeanRTu6ypG2OIaEv/ZHH/SUQ2iHOVyi5wAPjQ+HmnMuL0whK9ez8I/raWbtIg=="],
|
||||
|
||||
"@sapphire/snowflake": ["@sapphire/snowflake@3.5.3", "", {}, "sha512-jjmJywLAFoWeBi1W7994zZyiNWPIiqRRNAmSERxyg93xRGzNYvGjlZ0gR6x0F4gPRi2+0O6S71kOZYyr3cxaIQ=="],
|
||||
|
||||
"@types/bun": ["@types/bun@1.2.22", "", { "dependencies": { "bun-types": "1.2.22" } }, "sha512-5A/KrKos2ZcN0c6ljRSOa1fYIyCKhZfIVYeuyb4snnvomnpFqC0tTsEkdqNxbAgExV384OETQ//WAjl3XbYqQA=="],
|
||||
|
||||
"@types/node": ["@types/node@24.5.2", "", { "dependencies": { "undici-types": "~7.12.0" } }, "sha512-FYxk1I7wPv3K2XBaoyH2cTnocQEu8AOZ60hPbsyukMPLv5/5qr7V1i8PLHdl6Zf87I+xZXFvPCXYjiTFq+YSDQ=="],
|
||||
|
||||
"@types/react": ["@types/react@19.1.13", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-hHkbU/eoO3EG5/MZkuFSKmYqPbSVk5byPFa3e7y/8TybHiLMACgI8seVYlicwk7H5K/rI2px9xrQp/C+AUDTiQ=="],
|
||||
|
||||
"@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="],
|
||||
|
||||
"@vladfrangu/async_event_emitter": ["@vladfrangu/async_event_emitter@2.4.6", "", {}, "sha512-RaI5qZo6D2CVS6sTHFKg1v5Ohq/+Bo2LZ5gzUEwZ/WkHhwtGTCB/sVLw8ijOkAUxasZ+WshN/Rzj4ywsABJ5ZA=="],
|
||||
|
||||
"anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="],
|
||||
|
||||
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
|
||||
|
||||
"binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="],
|
||||
|
||||
"brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
|
||||
|
||||
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
|
||||
|
||||
"bun-types": ["bun-types@1.2.22", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-hwaAu8tct/Zn6Zft4U9BsZcXkYomzpHJX28ofvx7k0Zz2HNz54n1n+tDgxoWFGB4PcFvJXJQloPhaV2eP3Q6EA=="],
|
||||
|
||||
"chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="],
|
||||
|
||||
"concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="],
|
||||
|
||||
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
|
||||
|
||||
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
||||
|
||||
"discord-api-types": ["discord-api-types@0.38.26", "", {}, "sha512-xpmPviHjIJ6dFu1eNwNDIGQ3N6qmPUUYFVAx/YZ64h7ZgPkTcKjnciD8bZe8Vbeji7yS5uYljyciunpq0J5NSw=="],
|
||||
|
||||
"discord.js": ["discord.js@14.22.1", "", { "dependencies": { "@discordjs/builders": "^1.11.2", "@discordjs/collection": "1.5.3", "@discordjs/formatters": "^0.6.1", "@discordjs/rest": "^2.6.0", "@discordjs/util": "^1.1.1", "@discordjs/ws": "^1.2.3", "@sapphire/snowflake": "3.5.3", "discord-api-types": "^0.38.16", "fast-deep-equal": "3.1.3", "lodash.snakecase": "4.1.1", "magic-bytes.js": "^1.10.0", "tslib": "^2.6.3", "undici": "6.21.3" } }, "sha512-3k+Kisd/v570Jr68A1kNs7qVhNehDwDJAPe4DZ2Syt+/zobf9zEcuYFvsfIaAOgCa0BiHMfOOKQY4eYINl0z7w=="],
|
||||
|
||||
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
||||
|
||||
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
|
||||
|
||||
"fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="],
|
||||
|
||||
"glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
||||
|
||||
"has-flag": ["has-flag@3.0.0", "", {}, "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="],
|
||||
|
||||
"ignore-by-default": ["ignore-by-default@1.0.1", "", {}, "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA=="],
|
||||
|
||||
"is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="],
|
||||
|
||||
"is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="],
|
||||
|
||||
"is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="],
|
||||
|
||||
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
|
||||
|
||||
"lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
|
||||
|
||||
"lodash.snakecase": ["lodash.snakecase@4.1.1", "", {}, "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw=="],
|
||||
|
||||
"magic-bytes.js": ["magic-bytes.js@1.12.1", "", {}, "sha512-ThQLOhN86ZkJ7qemtVRGYM+gRgR8GEXNli9H/PMvpnZsE44Xfh3wx9kGJaldg314v85m+bFW6WBMaVHJc/c3zA=="],
|
||||
|
||||
"minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "^1.1.7" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="],
|
||||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
||||
"nodemon": ["nodemon@3.1.10", "", { "dependencies": { "chokidar": "^3.5.2", "debug": "^4", "ignore-by-default": "^1.0.1", "minimatch": "^3.1.2", "pstree.remy": "^1.1.8", "semver": "^7.5.3", "simple-update-notifier": "^2.0.0", "supports-color": "^5.5.0", "touch": "^3.1.0", "undefsafe": "^2.0.5" }, "bin": { "nodemon": "bin/nodemon.js" } }, "sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw=="],
|
||||
|
||||
"normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="],
|
||||
|
||||
"picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
||||
|
||||
"pstree.remy": ["pstree.remy@1.1.8", "", {}, "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w=="],
|
||||
|
||||
"readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
|
||||
|
||||
"semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
|
||||
|
||||
"simple-update-notifier": ["simple-update-notifier@2.0.0", "", { "dependencies": { "semver": "^7.5.3" } }, "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w=="],
|
||||
|
||||
"supports-color": ["supports-color@5.5.0", "", { "dependencies": { "has-flag": "^3.0.0" } }, "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="],
|
||||
|
||||
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
|
||||
|
||||
"touch": ["touch@3.1.1", "", { "bin": { "nodetouch": "bin/nodetouch.js" } }, "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA=="],
|
||||
|
||||
"ts-mixer": ["ts-mixer@6.0.4", "", {}, "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA=="],
|
||||
|
||||
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"typescript": ["typescript@5.9.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A=="],
|
||||
|
||||
"undefsafe": ["undefsafe@2.0.5", "", {}, "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA=="],
|
||||
|
||||
"undici": ["undici@6.21.3", "", {}, "sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw=="],
|
||||
|
||||
"undici-types": ["undici-types@7.12.0", "", {}, "sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ=="],
|
||||
|
||||
"ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="],
|
||||
|
||||
"@discordjs/rest/@discordjs/collection": ["@discordjs/collection@2.1.1", "", {}, "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg=="],
|
||||
|
||||
"@discordjs/ws/@discordjs/collection": ["@discordjs/collection@2.1.1", "", {}, "sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg=="],
|
||||
}
|
||||
}
|
||||
1
discord_bot/index.ts
Normal file
1
discord_bot/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
console.log("Hello via Bun!");
|
||||
9
discord_bot/node.js
Normal file
9
discord_bot/node.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import { Client, Events } from 'discord.js';
|
||||
|
||||
const client = new Client({ intents: [] });
|
||||
|
||||
client.once(Events.ClientReady, readyClient => {
|
||||
console.log(`Ready! Logged in as ${readyClient.user.tag}`);
|
||||
});
|
||||
|
||||
client.login("MTQyMDcyNzg0NjEwNzc0NjMwNQ.GEKESY.AXDX46SKpNplleXJU9jbmDXU0Dzlru7hf4rV-4");
|
||||
19
discord_bot/package.json
Normal file
19
discord_bot/package.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "discord_bot",
|
||||
"module": "index.ts",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^5"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "nodemon node nodejs"
|
||||
},
|
||||
"dependencies": {
|
||||
"discord.js": "^14.22.1",
|
||||
"nodemon": "^3.1.10"
|
||||
}
|
||||
}
|
||||
29
discord_bot/tsconfig.json
Normal file
29
discord_bot/tsconfig.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
// Environment setup & latest features
|
||||
"lib": ["ESNext"],
|
||||
"target": "ESNext",
|
||||
"module": "Preserve",
|
||||
"moduleDetection": "force",
|
||||
"jsx": "react-jsx",
|
||||
"allowJs": true,
|
||||
|
||||
// Bundler mode
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"noEmit": true,
|
||||
|
||||
// Best practices
|
||||
"strict": true,
|
||||
"skipLibCheck": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"noImplicitOverride": true,
|
||||
|
||||
// Some stricter flags (disabled by default)
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noPropertyAccessFromIndexSignature": false
|
||||
}
|
||||
}
|
||||
36
migrations/Version20250925100420.php
Normal file
36
migrations/Version20250925100420.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?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 Version20250925100420 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 customer_advert_payment_register (id SERIAL NOT NULL, advert_id INT DEFAULT NULL, amount DOUBLE PRECISION NOT NULL, create_at TIMESTAMP(0) WITHOUT TIME ZONE NOT NULL, numero_remise VARCHAR(255) DEFAULT NULL, cheque_num VARCHAR(255) DEFAULT NULL, type VARCHAR(255) NOT NULL, PRIMARY KEY(id))');
|
||||
$this->addSql('CREATE INDEX IDX_673F7A3ED07ECCB6 ON customer_advert_payment_register (advert_id)');
|
||||
$this->addSql('COMMENT ON COLUMN customer_advert_payment_register.create_at IS \'(DC2Type:datetime_immutable)\'');
|
||||
$this->addSql('ALTER TABLE customer_advert_payment_register ADD CONSTRAINT FK_673F7A3ED07ECCB6 FOREIGN KEY (advert_id) REFERENCES customer_advert_payment (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
$this->addSql('CREATE SCHEMA public');
|
||||
$this->addSql('ALTER TABLE customer_advert_payment_register DROP CONSTRAINT FK_673F7A3ED07ECCB6');
|
||||
$this->addSql('DROP TABLE customer_advert_payment_register');
|
||||
}
|
||||
}
|
||||
BIN
public/sound/alert.mp3
Normal file
BIN
public/sound/alert.mp3
Normal file
Binary file not shown.
24
src/Command/ExportComptable.php
Normal file
24
src/Command/ExportComptable.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Command;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Style\SymfonyStyle;
|
||||
|
||||
#[AsCommand(name: 'mainframe:export')]
|
||||
class ExportComptable extends Command
|
||||
{
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$io = new SymfonyStyle($input, $output);
|
||||
$io->title('Export comptable');
|
||||
|
||||
$lines =[];
|
||||
$lines[] = ['JournalCode','JournalLib','EcritureNum','EcritureDate','CompteNum','CompteLib','CompAuxNum','CompAuxLib','PieceRef','PieceDate','EcritureLib','Debit','Credit','EcritureLet','DateLet','ValidDate','Montantdevise','Idevise','DateRglt','ModeRglt','NatOp','IdClient'];
|
||||
|
||||
return Command::SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,15 @@ use Symfony\Component\Routing\Attribute\Route;
|
||||
|
||||
class AvatarController extends AbstractController
|
||||
{
|
||||
|
||||
#[Route(path: '/artemis/lockdown',name: 'artemis_lockdown',methods: ['GET', 'POST'])]
|
||||
public function artemisLockdown(): Response
|
||||
{
|
||||
return $this->json([
|
||||
'lockdown' => false
|
||||
]);
|
||||
}
|
||||
|
||||
#[Route(path: '/artemis/avatar',name: 'artemis_avatar',methods: ['GET', 'POST'])]
|
||||
public function artemis(): Response
|
||||
{
|
||||
|
||||
@@ -43,9 +43,31 @@ use Symfony\Component\Uid\Uuid;
|
||||
class CustomerController extends AbstractController
|
||||
{
|
||||
#[Route(path: '/artemis/intranet/customer',name: 'artemis_intranet_customer',methods: ['GET', 'POST'])]
|
||||
public function customers(CustomerRepository $customerRepository,Request $request,PaginatorInterface $paginator): Response
|
||||
public function customers(LoggerService $loggerService,CustomerRepository $customerRepository,EntityManagerInterface $entityManager,Request $request,PaginatorInterface $paginator): Response
|
||||
{
|
||||
|
||||
if($request->query->has('idCopy')){
|
||||
/** @var Customer $customer */
|
||||
$customer = $customerRepository->find($request->query->get('idCopy'));
|
||||
$newCustomer = clone $customer;
|
||||
$entityManager->persist($newCustomer);
|
||||
|
||||
foreach ($customer->getCustomerContacts() as $customerContact) {
|
||||
$contact = new CustomerContact();
|
||||
$contact->setName($customerContact->getName());
|
||||
$contact->setEmail($customerContact->getEmail());
|
||||
$contact->setPhone($customerContact->getPhone());
|
||||
$contact->setIsMain($customerContact->isMain());
|
||||
$contact->setSurname($customerContact->getSurname());
|
||||
$entityManager->persist($contact);
|
||||
$newCustomer->addCustomerContact($contact);
|
||||
}
|
||||
$entityManager->persist($newCustomer);
|
||||
$entityManager->flush();
|
||||
$loggerService->log('CREATE',"Copie d'une fiche client - ".$newCustomer->getRaisonSocial(),$this->getUser());
|
||||
$this->addFlash("success","Copie effectuée");
|
||||
return $this->redirectToRoute('artemis_intranet_customer');
|
||||
}
|
||||
return $this->render('artemis/intranet/customer.twig',[
|
||||
'customers' => $paginator->paginate($customerRepository->searchCustomer($request),$request->get('page',1),20),
|
||||
]);
|
||||
@@ -173,6 +195,10 @@ class CustomerController extends AbstractController
|
||||
}
|
||||
|
||||
if($request->query->has('idDevis') && $request->query->has('act')) {
|
||||
$devis = $entityManager->getRepository(CustomerDevis::class)->find($request->query->get('idDevis'));
|
||||
|
||||
$event = new CreateDevisCustomerEvent($devis,false);
|
||||
$eventDispatcher->dispatch($event);
|
||||
if($request->query->get('act') == "createAvisPayment") {
|
||||
/** @var CustomerDevis $devis */
|
||||
$devis = $entityManager->getRepository(CustomerDevis::class)->find($request->query->get('idDevis'));
|
||||
|
||||
@@ -101,6 +101,20 @@ class Customer
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $stancerId = null;
|
||||
|
||||
|
||||
public function __clone(): void
|
||||
{
|
||||
$this->id = null;
|
||||
$this->raisonSocial = "Copie - ".$this->raisonSocial;
|
||||
$this->codeComptable = "";
|
||||
$this->customerContacts = new ArrayCollection();
|
||||
$this->customerDns = new ArrayCollection();
|
||||
$this->customerDevis = new ArrayCollection();
|
||||
$this->customerAdvertPayments = new ArrayCollection();
|
||||
$this->customerOrders = new ArrayCollection();
|
||||
$this->stancerId = null;
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->customerContacts = new ArrayCollection();
|
||||
@@ -487,4 +501,9 @@ class Customer
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setId(null $null)
|
||||
{
|
||||
$this->id = $null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,9 +67,16 @@ class CustomerAdvertPayment
|
||||
|
||||
#[ORM\Column(nullable: true)]
|
||||
private ?\DateTimeImmutable $payAt = null;
|
||||
|
||||
/**
|
||||
* @var Collection<int, CustomerAdvertPaymentRegister>
|
||||
*/
|
||||
#[ORM\OneToMany(targetEntity: CustomerAdvertPaymentRegister::class, mappedBy: 'advert')]
|
||||
private Collection $customerAdvertPaymentRegisters;
|
||||
public function __construct()
|
||||
{
|
||||
$this->customerAdvertPaymentLines = new ArrayCollection();
|
||||
$this->customerAdvertPaymentRegisters = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
@@ -339,4 +346,34 @@ class CustomerAdvertPayment
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection<int, CustomerAdvertPaymentRegister>
|
||||
*/
|
||||
public function getCustomerAdvertPaymentRegisters(): Collection
|
||||
{
|
||||
return $this->customerAdvertPaymentRegisters;
|
||||
}
|
||||
|
||||
public function addCustomerAdvertPaymentRegister(CustomerAdvertPaymentRegister $customerAdvertPaymentRegister): static
|
||||
{
|
||||
if (!$this->customerAdvertPaymentRegisters->contains($customerAdvertPaymentRegister)) {
|
||||
$this->customerAdvertPaymentRegisters->add($customerAdvertPaymentRegister);
|
||||
$customerAdvertPaymentRegister->setAdvert($this);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function removeCustomerAdvertPaymentRegister(CustomerAdvertPaymentRegister $customerAdvertPaymentRegister): static
|
||||
{
|
||||
if ($this->customerAdvertPaymentRegisters->removeElement($customerAdvertPaymentRegister)) {
|
||||
// set the owning side to null (unless already changed)
|
||||
if ($customerAdvertPaymentRegister->getAdvert() === $this) {
|
||||
$customerAdvertPaymentRegister->setAdvert(null);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
116
src/Entity/CustomerAdvertPaymentRegister.php
Normal file
116
src/Entity/CustomerAdvertPaymentRegister.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use App\Repository\CustomerAdvertPaymentRegisterRepository;
|
||||
use Doctrine\DBAL\Types\DateImmutableType;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
#[ORM\Entity(repositoryClass: CustomerAdvertPaymentRegisterRepository::class)]
|
||||
class CustomerAdvertPaymentRegister
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\ManyToOne(inversedBy: 'customerAdvertPaymentRegisters')]
|
||||
private ?CustomerAdvertPayment $advert = null;
|
||||
|
||||
#[ORM\Column]
|
||||
private ?float $amount = null;
|
||||
|
||||
#[ORM\Column()]
|
||||
private ?\DateTimeImmutable $createAt = null;
|
||||
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $numeroRemise = null;
|
||||
|
||||
#[ORM\Column(length: 255, nullable: true)]
|
||||
private ?string $chequeNum = null;
|
||||
|
||||
#[ORM\Column(length: 255)]
|
||||
private ?string $type = null;
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getAdvert(): ?CustomerAdvertPayment
|
||||
{
|
||||
return $this->advert;
|
||||
}
|
||||
|
||||
public function setAdvert(?CustomerAdvertPayment $advert): static
|
||||
{
|
||||
$this->advert = $advert;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAmount(): ?float
|
||||
{
|
||||
return $this->amount;
|
||||
}
|
||||
|
||||
public function setAmount(float $amount): static
|
||||
{
|
||||
$this->amount = $amount;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \DateTimeImmutable|null
|
||||
*/
|
||||
public function getCreateAt(): ?\DateTimeImmutable
|
||||
{
|
||||
return $this->createAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DateTimeImmutable|null $createAt
|
||||
*/
|
||||
public function setCreateAt(?\DateTimeImmutable $createAt): self
|
||||
{
|
||||
$this->createAt = $createAt;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getNumeroRemise(): ?string
|
||||
{
|
||||
return $this->numeroRemise;
|
||||
}
|
||||
|
||||
public function setNumeroRemise(?string $numeroRemise): static
|
||||
{
|
||||
$this->numeroRemise = $numeroRemise;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getChequeNum(): ?string
|
||||
{
|
||||
return $this->chequeNum;
|
||||
}
|
||||
|
||||
public function setChequeNum(?string $chequeNul): static
|
||||
{
|
||||
$this->chequeNum = $chequeNul;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getType(): ?string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
public function setType(string $type): static
|
||||
{
|
||||
$this->type = $type;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
43
src/Repository/CustomerAdvertPaymentRegisterRepository.php
Normal file
43
src/Repository/CustomerAdvertPaymentRegisterRepository.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Entity\CustomerAdvertPaymentRegister;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<CustomerAdvertPaymentRegister>
|
||||
*/
|
||||
class CustomerAdvertPaymentRegisterRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, CustomerAdvertPaymentRegister::class);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @return CustomerAdvertPaymentRegister[] Returns an array of CustomerAdvertPaymentRegister objects
|
||||
// */
|
||||
// public function findByExampleField($value): array
|
||||
// {
|
||||
// return $this->createQueryBuilder('c')
|
||||
// ->andWhere('c.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->orderBy('c.id', 'ASC')
|
||||
// ->setMaxResults(10)
|
||||
// ->getQuery()
|
||||
// ->getResult()
|
||||
// ;
|
||||
// }
|
||||
|
||||
// public function findOneBySomeField($value): ?CustomerAdvertPaymentRegister
|
||||
// {
|
||||
// return $this->createQueryBuilder('c')
|
||||
// ->andWhere('c.exampleField = :val')
|
||||
// ->setParameter('val', $value)
|
||||
// ->getQuery()
|
||||
// ->getOneOrNullResult()
|
||||
// ;
|
||||
// }
|
||||
}
|
||||
@@ -4,13 +4,15 @@ namespace App\Service\Docuseal;
|
||||
|
||||
use App\Entity\CustomerDevis;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Vich\UploaderBundle\Templating\Helper\UploaderHelper;
|
||||
|
||||
class SignClient
|
||||
{
|
||||
private \Docuseal\Api $docuseal;
|
||||
|
||||
public function __construct(private readonly UrlGeneratorInterface $urlGenerator,private readonly EntityManagerInterface $entityManager)
|
||||
public function __construct(private readonly RequestStack $requestStack,private readonly UploaderHelper $uploaderHelper,private readonly UrlGeneratorInterface $urlGenerator,private readonly EntityManagerInterface $entityManager)
|
||||
{
|
||||
$this->docuseal = new \Docuseal\Api($_ENV['DOCUSIGN_KEY'], $_ENV['DOCUSIGN_URL']);
|
||||
|
||||
@@ -21,53 +23,30 @@ class SignClient
|
||||
|
||||
$t = new \DateTimeImmutable();
|
||||
|
||||
if($devis->getDevisSubmiterId() == null) {
|
||||
$submissionId = $this->docuseal->createSubmission([
|
||||
'template_id' => 1,
|
||||
'send_email' => false,
|
||||
'completed_redirect_url' => $this->urlGenerator->generate('app_sign_complete',['type'=>'devis','id'=>$devis->getId()],UrlGeneratorInterface::ABSOLUTE_URL),
|
||||
'submitters' => [
|
||||
if($devis->getDevisSubmiterId() == null) {
|
||||
|
||||
$submissionId = $this->docuseal->createSubmissionFromPdf([
|
||||
'name' => 'Devis N°'.$devis->getNumDevis(),
|
||||
'completed_redirect_url' => $this->urlGenerator->generate('app_sign_complete',['type'=>'devis','id'=>$devis->getId()],UrlGeneratorInterface::ABSOLUTE_URL),
|
||||
'send_email' => false,
|
||||
'documents' => [
|
||||
[
|
||||
'name' => 'devis',
|
||||
'file' => $this->requestStack->getCurrentRequest()->getSchemeAndHttpHost().$this->uploaderHelper->asset($devis,'devis'),
|
||||
]
|
||||
],
|
||||
'submitters' => [
|
||||
[
|
||||
'role' => 'Client',
|
||||
'role' => 'First Party',
|
||||
'email' => $devis->getCustomer()->mainContact()->getEmail(),
|
||||
'metadata' => [
|
||||
'type' =>'devis',
|
||||
'id' => $devis->getId(),
|
||||
],
|
||||
'fields' => [
|
||||
[
|
||||
'name' => 'Numéro devis',
|
||||
'value' => $devis->getNumDevis(),
|
||||
'readonly' => true,
|
||||
],
|
||||
[
|
||||
'name' => 'Raison Social',
|
||||
'value' => $devis->getCustomer()->getRaisonSocial(),
|
||||
'readonly' => true,
|
||||
],
|
||||
[
|
||||
'name' => 'Adresse',
|
||||
'value' => $devis->getCustomer()->getAddress(),
|
||||
'readonly' => true,
|
||||
],
|
||||
[
|
||||
'name' => 'Email',
|
||||
'value' => $devis->getCustomer()->mainContact()->getEmail(),
|
||||
'readonly' => true,
|
||||
],
|
||||
[
|
||||
'name' => 'Date Signature',
|
||||
'value' => 'Signée le ' . $t->format('d/m/Y H:i:s'),
|
||||
'readonly' => true,
|
||||
]
|
||||
]
|
||||
]
|
||||
],
|
||||
]);
|
||||
$devis->setDevisSubmiterId($submissionId['id']);
|
||||
$this->entityManager->persist($devis);
|
||||
$this->entityManager->flush();
|
||||
$submissionData = $this->docuseal->getSubmitter($devis->getDevisSubmiterId());
|
||||
]
|
||||
]);
|
||||
|
||||
$devis->setDevisSubmiterId($submissionId['id']);
|
||||
$this->entityManager->persist($devis);
|
||||
$this->entityManager->flush();
|
||||
$submissionData = $this->docuseal->getSubmitter($devis->getDevisSubmiterId());
|
||||
} else {
|
||||
$submissionData = $this->docuseal->getSubmitter($devis->getDevisSubmiterId());
|
||||
}
|
||||
|
||||
@@ -145,15 +145,16 @@ class DevisPdf extends FPDF
|
||||
// Position the summary block at the bottom of the page
|
||||
$this->SetY(-60);
|
||||
|
||||
$this->Cell(30,10,"{{Sign;type=signature;role=First Party}}", 0, 0, 'L');
|
||||
// Display the summary
|
||||
$this->SetFont('Arial', '', 12);
|
||||
$this->Cell(135, 10, mb_convert_encoding('Total HT :', 'ISO-8859-1', 'UTF-8'), 0, 0, 'R');
|
||||
$this->Cell(100, 10, mb_convert_encoding('Total HT :', 'ISO-8859-1', 'UTF-8'), 0, 0, 'R');
|
||||
$this->Cell(40, 10, number_format($totalHT, 2, ",") . " " . EURO, 0, 1, 'R');
|
||||
|
||||
$this->Cell(135, 10, mb_convert_encoding('TVA (20%) :', 'ISO-8859-1', 'UTF-8'), 0, 0, 'R');
|
||||
$this->Cell(40, 10, number_format($totalTVA, 2, ",") . " " . EURO, 0, 1, 'R');
|
||||
$this->Cell(35, 10, number_format($totalTVA, 2, ",") . " " . EURO, 0, 1, 'R');
|
||||
$this->SetFont('Arial', 'B', 12);
|
||||
$this->Cell(135, 10, mb_convert_encoding('Total :', 'ISO-8859-1', 'UTF-8'), 0, 0, 'R');
|
||||
$this->Cell(40, 10, number_format($totalTTC, 2, ",") . " " . EURO, 0, 1, 'R');
|
||||
$this->Cell(35, 10, number_format($totalTTC, 2, ",") . " " . EURO, 0, 1, 'R');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,5 +194,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<security-wall></security-wall>
|
||||
{#<ip-wall></ip-wall>#}
|
||||
<lockdown-wall></lockdown-wall>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -62,6 +62,7 @@
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-700">
|
||||
{% for customer in customers %}
|
||||
|
||||
<tr class="hover:bg-gray-700 transition relative hover:bg-gray-700 transition">
|
||||
<td class="px-6 py-4 whitespace-nowrap">
|
||||
<div class="text-sm font-semibold">{{ customer.type|trans }} - {{ customer.raisonSocial }}</div>
|
||||
@@ -70,11 +71,12 @@
|
||||
<div class="text-xs text-gray-400">{{ customer.mainContact.name }} {{ customer.mainContact.surname }}</div>
|
||||
</td>
|
||||
<td class="px-6 py-4 text-center text-sm">0</td>
|
||||
<td class="px-6 py-4 text-center text-sm">0</td>
|
||||
<td class="px-6 py-4 text-center text-sm">{{ customer.customerDns.count }}</td>
|
||||
<td class="px-6 py-4 text-center text-sm">0</td>
|
||||
<td class="px-6 py-4 text-center text-sm">0</td>
|
||||
<td class="px-6 py-4 text-center text-sm text-green-500 font-bold">Non</td>
|
||||
<td class="px-6 py-4 whitespace-nowrap text-sm text-center">
|
||||
<a href="{{ path('artemis_intranet_customer',{idCopy:customer.id}) }}" class="bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded mr-2">Copier le client</a>
|
||||
<a href="{{ path('artemis_intranet_customer_view',{id:customer.id}) }}" class="bg-blue-600 hover:bg-blue-700 text-white px-3 py-1 rounded mr-2">Voir</a>
|
||||
<a href="{{ path('artemis_intranet_customer_delete',{id:customer.id}) }}" class="bg-red-600 hover:bg-red-700 text-white px-3 py-1 rounded">Supprimer</a>
|
||||
</td>
|
||||
|
||||
Reference in New Issue
Block a user