From 14bd394982df581abd57def4e5be0f0f88557f3f Mon Sep 17 00:00:00 2001 From: solocla Date: Wed, 14 Oct 2026 10:21:55 +0200 Subject: [PATCH] fixed shop --- ...261010162855_add_setup_state_to_option.php | 37 + public/assets/css/yb-shop.css | 1015 ++++++++++++++ public/assets/js/yb-shop.js | 1186 +++++++++++++++++ public/class/SchoolScope.php | 1 + public/class/SchoolSetup.php | 303 +++++ public/class/ShopService.php | 976 ++++++++++++++ public/include/sidebar.php | 64 +- public/ordersummary.php | 2 - public/package_rules.php | 305 +++++ public/school_orders.php | 1123 ++++++++++++++++ public/school_setup.php | 510 +++++++ public/shop.php | 128 ++ public/shop_checkout.php | 389 ++++++ public/shop_order.php | 285 ++++ .../schools/1/logo-40be84a1d014d11e.png | Bin 0 -> 132161 bytes 15 files changed, 6312 insertions(+), 12 deletions(-) create mode 100644 db/migrations/20261010162855_add_setup_state_to_option.php create mode 100644 public/assets/css/yb-shop.css create mode 100644 public/assets/js/yb-shop.js create mode 100644 public/class/SchoolSetup.php create mode 100644 public/class/ShopService.php create mode 100644 public/package_rules.php create mode 100644 public/school_orders.php create mode 100644 public/school_setup.php create mode 100644 public/shop.php create mode 100644 public/shop_checkout.php create mode 100644 public/shop_order.php create mode 100644 public/uploads/schools/1/logo-40be84a1d014d11e.png diff --git a/db/migrations/20261010162855_add_setup_state_to_option.php b/db/migrations/20261010162855_add_setup_state_to_option.php new file mode 100644 index 0000000..078d9a3 --- /dev/null +++ b/db/migrations/20261010162855_add_setup_state_to_option.php @@ -0,0 +1,37 @@ +table('option') + ->addColumn('setup_state', 'text', ['null' => true, 'comment' => 'JSON percorso Primi passi']) + ->addColumn('setup_completed_at', 'datetime', ['null' => true]) + ->update(); + + // Scuole che hanno già ordini o prenotazioni: percorso considerato concluso + $this->execute( + "UPDATE `option` o SET o.setup_completed_at = NOW() + WHERE EXISTS (SELECT 1 FROM orderbook ob WHERE ob.idschool = o.idschool) + OR EXISTS (SELECT 1 FROM bookingclass b WHERE b.idschool = o.idschool)" + ); + } + + public function down(): void + { + $this->table('option') + ->removeColumn('setup_state') + ->removeColumn('setup_completed_at') + ->update(); + } +} diff --git a/public/assets/css/yb-shop.css b/public/assets/css/yb-shop.css new file mode 100644 index 0000000..d74c1af --- /dev/null +++ b/public/assets/css/yb-shop.css @@ -0,0 +1,1015 @@ +/* YogiBook - negozio della scuola (webapp; riutilizzabile dal plugin WordPress) */ +.ys-wrap { + --ys-ink: #1e4a4f; + --ys-teal: #2f7f84; + --ys-aqua: #dbf6f9; + --ys-cream: #f8efe4; + --ys-sand: #e2ceb1; + --ys-text: #24363a; + --ys-muted: #5b6b6d; + --ys-line: #dce7e8; + max-width: 1120px; + margin: 0 auto; + color: var(--ys-text); + font-size: 15px; +} +.ys-wrap * { + box-sizing: border-box; +} +.ys-wrap button { + font-family: inherit; +} +.ys-wrap a { + color: var(--ys-teal); +} + +.ys-staffnote { + background: #fff8ec; + border: 1px solid #eed9b7; + color: #6b4b1e; + border-radius: 12px; + padding: 10px 14px; + font-size: 13px; + margin-bottom: 14px; + display: flex; + gap: 8px; + align-items: center; +} +.ys-empty { + text-align: center; + background: #fff; + border-radius: 20px; + padding: 48px 20px; + box-shadow: 0 4px 20px rgba(30, 74, 79, 0.06); +} +.ys-empty i { + font-size: 42px; + color: #9fcfd2; +} +.ys-empty h2 { + font-size: 22px; + color: var(--ys-ink); + margin: 10px 0 6px; + font-weight: 700; +} +.ys-empty p { + color: var(--ys-muted); +} + +/* Intestazione catalogo */ +.ys-head { + display: flex; + justify-content: space-between; + gap: 18px; + flex-wrap: wrap; + align-items: flex-end; + margin-bottom: 18px; +} +.ys-h1 { + margin: 0; + font-size: 28px; + line-height: 1.15; + font-weight: 700; + color: var(--ys-ink); +} +.ys-lead { + margin: 6px 0 0; + color: var(--ys-muted); + font-size: 15px; +} +.ys-mine { + background: #fff; + border: 1px solid var(--ys-line); + border-radius: 16px; + padding: 12px 16px; + min-width: 260px; +} +.ys-mine b { + display: block; + font-size: 12px; + text-transform: uppercase; + letter-spacing: 0.05em; + color: var(--ys-teal); + margin-bottom: 4px; +} +.ys-mine div { + font-size: 14px; + display: flex; + justify-content: space-between; + gap: 12px; +} +.ys-mine span { + color: var(--ys-muted); + white-space: nowrap; +} +.ys-alert { + display: flex; + gap: 10px; + align-items: flex-start; + border-radius: 14px; + padding: 12px 16px; + font-size: 14px; + line-height: 1.45; + margin-bottom: 16px; + background: var(--ys-cream); + border: 1px solid #ead9bf; + color: #6b4b1e; +} +.ys-alert i { + font-size: 20px; + flex-shrink: 0; +} + +/* Filtri */ +.ys-filters { + display: flex; + gap: 8px; + flex-wrap: wrap; + align-items: center; + margin-bottom: 18px; +} +.ys-pill { + border: 1px solid var(--ys-line); + background: #fff; + color: var(--ys-text); + border-radius: 999px; + padding: 8px 16px; + font-weight: 600; + font-size: 14px; + min-height: 40px; + cursor: pointer; +} +.ys-pill:hover { + border-color: #9fcfd2; +} +.ys-pill.on { + background: var(--ys-ink); + border-color: var(--ys-ink); + color: #fff; +} +.ys-select { + border: 1px solid var(--ys-line); + border-radius: 999px; + padding: 8px 14px; + font-size: 14px; + min-height: 40px; + background: #fff; + color: var(--ys-text); + margin-left: auto; +} + +/* Griglia prodotti */ +.ys-grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); + gap: 18px; +} +.ys-card { + display: flex; + flex-direction: column; + text-align: left; + background: #fff; + border: 1px solid var(--ys-line); + border-radius: 20px; + overflow: hidden; + padding: 0; + cursor: pointer; + box-shadow: 0 2px 12px rgba(30, 74, 79, 0.05); + transition: + transform 0.15s, + box-shadow 0.15s; +} +.ys-card:hover { + transform: translateY(-2px); + box-shadow: 0 8px 24px rgba(30, 74, 79, 0.1); +} +.ys-card:focus-visible { + outline: 3px solid #6fbabe; + outline-offset: 2px; +} +.ys-card-img { + height: 150px; + background: var(--ys-aqua) center / cover no-repeat; + position: relative; + display: flex; + align-items: flex-end; + padding: 14px; +} +.ys-card-img .mark { + font-size: 30px; + font-weight: 800; + color: var(--ys-ink); + opacity: 0.85; +} +.ys-card-img .ys-badge { + position: absolute; + top: 12px; + left: 12px; +} +.ys-card-body { + padding: 14px 16px 16px; + display: flex; + flex-direction: column; + gap: 5px; + flex: 1; +} +.ys-card-title { + font-size: 17px; + font-weight: 700; + color: var(--ys-ink); + line-height: 1.25; +} +.ys-card-sub { + font-size: 13px; + color: var(--ys-muted); + line-height: 1.4; +} +.ys-card-rule { + font-size: 12px; + color: var(--ys-teal); + font-weight: 600; +} +.ys-card-foot { + margin-top: auto; + padding-top: 8px; + display: flex; + justify-content: space-between; + align-items: baseline; + gap: 8px; +} +.ys-price-from { + font-size: 18px; + font-weight: 800; + color: var(--ys-ink); +} +.ys-price-from small { + font-size: 12px; + font-weight: 600; + color: var(--ys-muted); +} +.ys-badge { + display: inline-block; + background: #fff; + color: #7a5a2e; + font-size: 11px; + font-weight: 800; + padding: 3px 10px; + border-radius: 10px; + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08); +} +.ys-badge.muted { + background: #eef0f3; + color: #4b5563; + box-shadow: none; +} +.ys-noresult { + text-align: center; + color: var(--ys-muted); + padding: 40px 10px; +} + +/* Scheda prodotto */ +.ys-back { + display: inline-flex; + align-items: center; + gap: 6px; + border: none; + background: none; + color: var(--ys-teal); + font-weight: 700; + font-size: 14px; + padding: 8px 0; + min-height: 44px; + cursor: pointer; +} +.ys-product { + display: grid; + grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); + gap: 32px; + align-items: start; +} +.ys-gallery-main { + aspect-ratio: 4 / 3; + border-radius: 22px; + background: var(--ys-aqua) center / cover no-repeat; + display: flex; + align-items: flex-end; + padding: 22px; +} +.ys-gallery-main .mark { + font-size: 54px; + font-weight: 800; + color: var(--ys-ink); + opacity: 0.8; +} +.ys-thumbs { + display: flex; + gap: 8px; + margin-top: 10px; + flex-wrap: wrap; +} +.ys-thumb { + width: 64px; + height: 64px; + border-radius: 12px; + border: 2px solid transparent; + padding: 0; + background: #eee center / cover no-repeat; + cursor: pointer; +} +.ys-thumb.on { + border-color: var(--ys-teal); +} +.ys-info { + display: flex; + flex-direction: column; + gap: 16px; +} +.ys-title { + margin: 0; + font-size: 28px; + line-height: 1.2; + font-weight: 700; + color: var(--ys-ink); +} +.ys-subtitle { + margin: 0; + font-size: 16px; + color: var(--ys-muted); +} +.ys-desc { + line-height: 1.6; +} +.ys-desc p { + margin: 0 0 8px; +} +.ys-h3 { + margin: 0 0 8px; + font-size: 14px; + font-weight: 700; + color: var(--ys-ink); +} +.ys-li { + display: flex; + gap: 10px; + align-items: flex-start; + line-height: 1.45; + font-size: 14px; + margin-bottom: 6px; +} +.ys-check { + width: 22px; + height: 22px; + border-radius: 50%; + background: var(--ys-aqua); + color: var(--ys-teal); + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + font-size: 15px; +} +.ys-dot { + width: 7px; + height: 7px; + border-radius: 50%; + background: #c9a876; + margin-top: 7px; + flex-shrink: 0; +} +.ys-cons { + background: #fff; + border: 1px solid #e8dcc9; + border-radius: 14px; + padding: 12px 14px; +} +.ys-chips { + display: flex; + flex-wrap: wrap; + gap: 6px; +} +.ys-chip { + font-size: 13px; + background: #fff; + border: 1px solid var(--ys-line); + border-radius: 20px; + padding: 5px 11px; +} +.ys-info2 { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 10px; +} +.ys-info2 div { + background: #fff; + border-radius: 14px; + padding: 12px; + font-size: 13px; + line-height: 1.45; +} +.ys-info2 b { + display: block; + font-size: 12px; + color: var(--ys-teal); + text-transform: uppercase; + letter-spacing: 0.04em; + margin-bottom: 4px; +} +.ys-muted { + font-size: 13px; + color: var(--ys-muted); + line-height: 1.4; +} + +/* Opzioni e scelte */ +.ys-options { + display: flex; + flex-direction: column; + gap: 10px; +} +.ys-opt { + display: flex; + align-items: center; + gap: 12px; + width: 100%; + text-align: left; + background: #fff; + border: 1px solid #d5e3e4; + border-radius: 16px; + padding: 14px; + min-height: 64px; + cursor: pointer; +} +.ys-opt.sel { + background: #f4fafa; + border: 2px solid var(--ys-teal); + padding: 13px; +} +.ys-opt:disabled { + opacity: 0.55; + cursor: not-allowed; +} +.ys-radio { + width: 22px; + height: 22px; + border-radius: 50%; + border: 2px solid #a9bfc1; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; +} +.ys-opt.sel .ys-radio { + border-color: var(--ys-teal); +} +.ys-opt.sel .ys-radio::after { + content: ""; + width: 10px; + height: 10px; + border-radius: 50%; + background: var(--ys-teal); +} +.ys-box { + width: 24px; + height: 24px; + border-radius: 7px; + border: 2px solid #a9bfc1; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; + color: #fff; + font-size: 16px; +} +.ys-opt.sel .ys-box { + background: var(--ys-teal); + border-color: var(--ys-teal); +} +.ys-opt-main { + display: flex; + flex-direction: column; + gap: 2px; + flex: 1; + min-width: 0; +} +.ys-opt-title { + font-weight: 700; + font-size: 16px; + color: var(--ys-ink); +} +.ys-opt-note { + font-size: 12px; + color: var(--ys-teal); + font-weight: 600; +} +.ys-opt-price { + display: flex; + flex-direction: column; + align-items: flex-end; + flex-shrink: 0; +} +.ys-opt-price s { + font-size: 13px; + color: #6b7a7c; +} +.ys-opt-price b { + font-size: 19px; + color: var(--ys-ink); +} +.ys-seats { + font-size: 12px; + font-weight: 700; + padding: 3px 8px; + border-radius: 10px; + flex-shrink: 0; + background: #e9f7f0; + color: #1a6b47; + white-space: nowrap; +} +.ys-seats.low { + background: #fbede3; + color: #9a4a14; +} +.ys-seats.full { + background: #fdecea; + color: #a33a1f; +} +.ys-seats.none, +.ys-seats.mine { + background: #eef0f3; + color: #4b5563; +} +.ys-pillcount { + align-self: flex-start; + font-size: 13px; + font-weight: 700; + color: var(--ys-teal); + background: var(--ys-aqua); + padding: 4px 10px; + border-radius: 10px; +} +.ys-note { + display: flex; + gap: 10px; + background: #fff; + border: 1px dashed #b9d7d9; + border-radius: 14px; + padding: 12px 14px; + font-size: 13px; + line-height: 1.45; +} +.ys-panel { + background: #fff; + border-radius: 18px; + padding: 18px; + display: flex; + flex-direction: column; + gap: 14px; +} +.ys-label { + font-size: 14px; + font-weight: 600; + color: var(--ys-ink); + margin-bottom: 6px; + display: block; +} +.ys-input { + width: 100%; + border: 1px solid #cfdedf; + border-radius: 12px; + padding: 12px; + font-size: 15px; + color: var(--ys-text); + background: #fff; +} +.ys-input:focus { + outline: none; + border-color: var(--ys-teal); + box-shadow: 0 0 0 3px rgba(47, 127, 132, 0.15); +} +.ys-choose { + max-width: 680px; + display: flex; + flex-direction: column; + gap: 14px; +} + +/* Barra acquisto */ +.ys-buy { + position: sticky; + bottom: 0; + z-index: 4; + margin-top: 22px; + background: #fff; + border: 1px solid #e3eced; + border-radius: 18px; + padding: 12px 16px; + display: flex; + align-items: center; + gap: 14px; + box-shadow: 0 -4px 20px rgba(30, 74, 79, 0.06); +} +.ys-buy .lbl { + font-size: 12px; + color: var(--ys-muted); +} +.ys-buy .amt { + font-size: 24px; + font-weight: 800; + color: var(--ys-ink); + line-height: 1.1; +} +.ys-btn { + border: none; + border-radius: 14px; + min-height: 50px; + padding: 0 24px; + font-size: 16px; + font-weight: 700; + background: var(--ys-teal); + color: #fff; + cursor: pointer; + display: inline-flex; + align-items: center; + gap: 8px; + text-decoration: none; +} +.ys-btn:hover { + background: var(--ys-ink); + color: #fff; +} +.ys-btn:disabled { + background: #c9d6d7; + cursor: not-allowed; +} + +/* Schede Prodotti / Orario */ +.ys-tabs { + display: inline-flex; + gap: 4px; + background: #e9f1f1; + border-radius: 12px; + padding: 4px; + margin-bottom: 16px; +} +.ys-tab { + border: none; + background: transparent; + border-radius: 9px; + padding: 9px 16px; + font-weight: 700; + font-size: 14px; + color: var(--ys-muted); + cursor: pointer; + min-height: 40px; + display: inline-flex; + align-items: center; + gap: 6px; +} +.ys-tab.on { + background: #fff; + color: var(--ys-ink); + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08); +} + +/* Orario settimanale */ +.ys-week { + display: grid; + grid-template-columns: repeat(var(--ys-cols, 5), minmax(0, 1fr)); + gap: 10px; + align-items: start; +} +.ys-day { + background: #fff; + border-radius: 16px; + padding: 10px; + display: flex; + flex-direction: column; + gap: 8px; + min-height: 120px; + border: 1px solid var(--ys-line); +} +.ys-day-name { + font-size: 13px; + font-weight: 800; + text-transform: uppercase; + letter-spacing: 0.05em; + color: var(--ys-ink); + text-align: center; + padding: 4px 0 6px; + border-bottom: 1px solid #eef3f3; +} +.ys-day-empty { + text-align: center; + color: #b7c4c5; + padding: 10px 0; +} +.ys-slot { + --ys-c: #6fbabe; + position: relative; + text-align: left; + border: 1px solid var(--ys-line); + border-left: 5px solid var(--ys-c); + background: #fff; + border-radius: 12px; + padding: 9px 10px 10px; + display: flex; + flex-direction: column; + gap: 3px; + cursor: pointer; + width: 100%; +} +.ys-slot:hover { + background: #f4fafa; +} +.ys-slot.sel { + background: #f4fafa; + border-color: var(--ys-teal); + border-left-color: var(--ys-c); + box-shadow: 0 0 0 2px var(--ys-teal); +} +.ys-slot .t { + font-size: 12px; + font-weight: 800; + color: var(--ys-teal); +} +.ys-slot .n { + font-size: 14px; + font-weight: 700; + color: var(--ys-ink); + line-height: 1.25; +} +.ys-slot .m { + font-size: 12px; + color: var(--ys-muted); +} +.ys-slot .ys-seats { + align-self: flex-start; + margin-top: 4px; + font-size: 11px; + padding: 2px 7px; +} +.ys-calpanel { + margin-top: 18px; + background: #fff; + border: 1px solid var(--ys-line); + border-radius: 20px; + padding: 18px; + scroll-margin-top: 90px; +} +.ys-calpanel-head { + --ys-c: #6fbabe; + display: flex; + justify-content: space-between; + gap: 12px; + align-items: flex-start; + border-left: 5px solid var(--ys-c); + padding-left: 12px; + margin-bottom: 12px; +} +@media (max-width: 860px) { + .ys-week { + grid-template-columns: minmax(0, 1fr); + } + .ys-day { + min-height: 0; + } + .ys-day-name { + text-align: left; + } + .ys-day:has(.ys-day-empty) { + display: none; + } +} + +@media (max-width: 860px) { + .ys-product { + grid-template-columns: minmax(0, 1fr); + gap: 18px; + } + .ys-select { + margin-left: 0; + } +} +@media (max-width: 520px) { + .ys-h1, + .ys-title { + font-size: 24px; + } + .ys-info2 { + grid-template-columns: minmax(0, 1fr); + } + .ys-buy { + border-radius: 0; + margin-left: -12px; + margin-right: -12px; + } +} + +/* ===== Checkout e ordine ===== */ +.ys-co-grid { + display: grid; + grid-template-columns: minmax(0, 1.4fr) minmax(300px, 1fr); + gap: 18px; + align-items: start; +} +.ys-co-main { + display: flex; + flex-direction: column; + gap: 16px; +} +.ys-co-side { + position: sticky; + top: 90px; + margin: 0; +} +.ys-co-prod { + display: flex; + justify-content: space-between; + gap: 14px; + align-items: flex-start; + padding-bottom: 12px; + border-bottom: 1px solid #e3eced; +} +.ys-kv { + display: grid; + grid-template-columns: minmax(110px, auto) 1fr; + gap: 8px 16px; + font-size: 14px; + margin: 0; +} +.ys-kv dt { + color: var(--ys-muted); + font-weight: 600; +} +.ys-kv dd { + margin: 0; + color: var(--ys-text); + word-break: break-word; +} +.ys-coupon { + display: flex; + flex-direction: column; + gap: 10px; + margin: 0; +} +.ys-co-ok { + display: flex; + justify-content: space-between; + align-items: center; + gap: 8px; + background: #e9f7f0; + color: #1a6b47; + border-radius: 12px; + padding: 8px 12px; + font-weight: 600; + font-size: 14px; +} +.ys-co-err { + font-size: 13px; + font-weight: 600; + color: #a33a1f; +} +.ys-linkbtn { + border: none; + background: none; + color: var(--ys-teal); + font-weight: 700; + text-decoration: underline; + padding: 6px 4px; + min-height: 36px; + cursor: pointer; + font-size: 14px; +} +.ys-btn-light { + background: #fff; + color: var(--ys-teal); + border: 1px solid var(--ys-teal); +} +.ys-btn-light:hover { + background: #f4fafa; + color: var(--ys-ink); +} +label.ys-opt { + margin: 0; +} +.ys-radio-input { + position: absolute; + opacity: 0; + pointer-events: none; +} +.ys-co-totals { + display: flex; + flex-direction: column; + gap: 6px; + font-size: 14px; + border-top: 1px solid #e3eced; + padding-top: 12px; +} +.ys-co-totals div { + display: flex; + justify-content: space-between; + gap: 12px; +} +.ys-co-totals .ok { + color: #1a6b47; +} +.ys-co-totals .tot { + font-size: 22px; + font-weight: 800; + color: var(--ys-ink); + padding-top: 4px; +} +.ys-terms { + display: flex; + gap: 10px; + align-items: flex-start; + font-size: 13px; + line-height: 1.45; + cursor: pointer; + margin: 0; + padding: 6px; + border-radius: 10px; +} +.ys-terms input { + width: 20px; + height: 20px; + margin: 0; + accent-color: var(--ys-teal); + flex-shrink: 0; +} +.ys-terms.need { + background: #fdecea; + color: #8f2f24; +} +.ys-terms-text { + max-height: 220px; + overflow-y: auto; + font-size: 13px; + line-height: 1.5; + background: #fafbfc; + border: 1px solid #eef0f3; + border-radius: 10px; + padding: 10px 12px; + color: var(--ys-text); +} +.ys-done { + text-align: center; + display: flex; + flex-direction: column; + align-items: center; + gap: 8px; + padding: 10px 0 22px; +} +.ys-done-ico { + width: 72px; + height: 72px; + border-radius: 50%; + background: var(--ys-aqua); + color: var(--ys-teal); + display: flex; + align-items: center; + justify-content: center; + font-size: 38px; + box-shadow: 10px 0 0 var(--ys-cream); +} +.ys-bank { + border: 2px dashed #9fcfd2; + margin-bottom: 16px; +} +.ys-mono { + font-family: ui-monospace, SFMono-Regular, Menlo, monospace; + letter-spacing: 0.03em; +} +.ys-status { + display: inline-block; + font-size: 12px; + font-weight: 700; + padding: 4px 10px; + border-radius: 20px; + white-space: nowrap; +} +.ys-status.ok { + background: #e7f7ee; + color: #1a7f52; +} +.ys-status.warn { + background: #fff4e0; + color: #92560b; +} +.ys-status.muted { + background: #eef0f3; + color: #4b5563; +} +.ys-checkout .ys-panel { + margin-bottom: 0; + border: 1px solid var(--ys-line); +} +@media (max-width: 860px) { + .ys-co-grid { + grid-template-columns: minmax(0, 1fr); + } + .ys-co-side { + position: static; + } +} diff --git a/public/assets/js/yb-shop.js b/public/assets/js/yb-shop.js new file mode 100644 index 0000000..fc38971 --- /dev/null +++ b/public/assets/js/yb-shop.js @@ -0,0 +1,1186 @@ +/*! + * YogiBook - negozio della scuola. + * Catalogo, scheda prodotto e scelte (classe fissa, data, destinatario del buono). + * Pensato per essere riusato anche dal plugin WordPress: + * YBShop.mount(elemento, dati, { onCheckout: function (scelta) { ... } }) + * "dati" è l'oggetto prodotto da ShopService::catalog(). + * Indirizzi: #/slug (scheda prodotto), #/slug/scegli (passo delle scelte). + */ +(function () { + "use strict"; + + var MESI = [ + "gennaio", + "febbraio", + "marzo", + "aprile", + "maggio", + "giugno", + "luglio", + "agosto", + "settembre", + "ottobre", + "novembre", + "dicembre", + ]; + var TONES = { + single: "#DBF6F9", + fixed: "#DBF6F9", + free: "#F8EFE4", + membership: "#F8EFE4", + voucher: "#E2CEB1", + }; + var GROUPS = [ + ["single", "Per iniziare"], + ["fixed", "Classe fissa"], + ["free", "Flessibili"], + ["membership", "Tessera"], + ["voucher", "Regali"], + ]; + + function esc(s) { + return String(s === null || s === undefined ? "" : s).replace( + /[&<>"']/g, + function (c) { + return { + "&": "&", + "<": "<", + ">": ">", + '"': """, + "'": "'", + }[c]; + }, + ); + } + function euro(n) { + return ( + Number(n).toLocaleString("it-IT", { + minimumFractionDigits: 2, + maximumFractionDigits: 2, + }) + " €" + ); + } + function fmtDate(iso) { + var p = String(iso).split("-"); + return ( + parseInt(p[2], 10) + " " + MESI[parseInt(p[1], 10) - 1] + " " + p[0] + ); + } + function addDays(iso, n) { + var p = iso.split("-"), + d = new Date(+p[0], +p[1] - 1, +p[2] + n); + return ( + d.getFullYear() + + "-" + + String(d.getMonth() + 1).padStart(2, "0") + + "-" + + String(d.getDate()).padStart(2, "0") + ); + } + function unitLabel(n, unit) { + var l = { + days: ["giorno", "giorni"], + weeks: ["settimana", "settimane"], + months: ["mese", "mesi"], + }[unit] || ["", ""]; + return n + " " + (n === 1 ? l[0] : l[1]); + } + + function mount(root, DATA, opts) { + opts = opts || {}; + // cls = classe scelta nell'orario; prefSvc = classe da preselezionare nella scheda (classe fissa) + var S = { + filter: "", + cat: 0, + pid: null, + vid: null, + picked: [], + occ: null, + rName: "", + rEmail: "", + rMsg: "", + img: 0, + cls: 0, + prefSvc: 0, + from: "", + }; + var lastView = null; + + /* ---------------- dati ---------------- */ + function byId(id) { + for (var i = 0; i < DATA.products.length; i++) + if (DATA.products[i].id === id) return DATA.products[i]; + return null; + } + function bySlug(slug) { + for (var i = 0; i < DATA.products.length; i++) + if (DATA.products[i].slug === slug) return DATA.products[i]; + return null; + } + function prod() { + return byId(S.pid); + } + function variant(p) { + p = p || prod(); + if (!p) return null; + for (var i = 0; i < p.variants.length; i++) + if (p.variants[i].id === S.vid) return p.variants[i]; + return null; + } + function svc(id) { + return DATA.services[id] || null; + } + function needsChoose(p) { + return ( + !!p && + (p.mode === "fixed" || + p.mode === "single" || + p.mode === "voucher") + ); + } + + function mark(p) { + if (p.mode === "fixed") return p.slots === 2 ? "2×" : "1×"; + if (p.mode === "single") return p.once ? "Prova" : "1"; + if (p.mode === "membership") return "Tessera"; + if (p.mode === "voucher") return "Regalo"; + var v = p.variants[0]; + return v.lessons ? String(v.lessons) : "∞"; + } + function ruleLine(p) { + var lessons = p.variants + .map(function (v) { + return v.lessons; + }) + .filter(Boolean); + var range = lessons.length + ? (Math.min.apply(null, lessons) === + Math.max.apply(null, lessons) + ? Math.min.apply(null, lessons) + : Math.min.apply(null, lessons) + + "–" + + Math.max.apply(null, lessons)) + " lezioni" + : ""; + if (p.mode === "fixed") + return ( + (p.slots === 2 + ? "2 classi fisse a settimana" + : "1 classe fissa a settimana") + + (range ? " · " + range : "") + ); + if (p.mode === "free") + return ( + "Prenoti tu" + + (p.weekly ? " · max " + p.weekly + "/sett." : "") + + (range ? " · " + range : "") + ); + if (p.mode === "single") return "Scegli giorno e ora"; + if (p.mode === "membership") return "Quota associativa"; + return "Da regalare con un codice"; + } + function validityText(p, v) { + if (p.mode === "membership") { + if (v.vmode === "calendar_year") + return "Valida fino al " + fmtDate(DATA.yearEnd); + if (v.vmode === "season") + return "Valida fino al " + fmtDate(DATA.seasonEnd); + if (v.vmode === "duration" && v.vvalue) + return ( + "Valida " + + unitLabel(v.vvalue, v.vunit) + + " dall'acquisto" + ); + return "Senza scadenza"; + } + if (p.mode === "voucher") + return v.vvalue + ? "Il buono scade dopo " + unitLabel(v.vvalue, v.vunit) + : "Il buono non scade"; + if (p.mode === "single") return "Valida per la lezione che scegli"; + if (v.vmode === "none" || !v.vvalue) return "Senza scadenza"; + return ( + "Da usare entro " + + unitLabel(v.vvalue, v.vunit) + + (v.vstart === "purchase" + ? " dall'acquisto" + : " dalla prima lezione") + ); + } + + /* ---------------- posti ---------------- */ + // Classe fissa: minimo dei posti liberi sulle prossime N lezioni coperte dal pacchetto + function fixedSeats(sid, p, v) { + var s = svc(sid); + var n = v && v.lessons ? Math.ceil(v.lessons / (p.slots || 1)) : 8; + var occ = s ? s.occ.slice(0, n) : []; + if (!occ.length) + return { + cls: "none", + text: "Nessuna lezione in calendario", + ok: false, + }; + if (s.cap === null) + return { cls: "", text: "Posti disponibili", ok: true }; + var min = Math.min.apply( + null, + occ.map(function (o) { + return o.free; + }), + ); + if (min <= 0) + return { cls: "full", text: "Al completo", ok: false }; + return { + cls: min <= 2 ? "low" : "", + text: min === 1 ? "Ultimo posto" : min + " posti liberi", + ok: true, + }; + } + function seatsBadge(o) { + if (o.mine) + return { cls: "mine", text: "Sei già iscritta", ok: false }; + if (o.free === null) + return { cls: "", text: "Posti disponibili", ok: true }; + if (o.free <= 0) + return { cls: "full", text: "Al completo", ok: false }; + return { + cls: o.free <= 2 ? "low" : "", + text: o.free === 1 ? "Ultimo posto" : o.free + " posti", + ok: true, + }; + } + function singleOccurrences(p) { + var limit = addDays(DATA.today, DATA.singleDays || 21), + list = []; + p.services.forEach(function (sid) { + var s = svc(sid); + if (!s) return; + s.occ.forEach(function (o) { + if (o.date <= limit) list.push({ sid: sid, o: o, s: s }); + }); + }); + list.sort(function (a, b) { + return (a.o.date + a.o.time).localeCompare(b.o.date + b.o.time); + }); + return list.slice(0, 40); + } + function chooseValid(p) { + if (!p) return false; + if (p.mode === "fixed") return S.picked.length === (p.slots || 1); + if (p.mode === "single") return !!S.occ; + if (p.mode === "voucher") + return ( + S.rName.trim() !== "" && + /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(S.rEmail.trim()) + ); + return true; + } + + /* ---------------- render ---------------- */ + function cover(p, cls) { + var img = p.cover || (p.gallery && p.gallery[0]) || ""; + return img + ? '
" + : '
' + + esc(mark(p)) + + ""; + } + + var DAYS = [ + "Domenica", + "Lunedì", + "Martedì", + "Mercoledì", + "Giovedì", + "Venerdì", + "Sabato", + ]; + var DAY_ORDER = [1, 2, 3, 4, 5, 6, 0]; + var CAT_COLORS = [ + "#6FBABE", + "#E2A86B", + "#9C8FD6", + "#7FB77E", + "#E58F9E", + "#5A9BD5", + "#C9A876", + ]; + + function catColor(s) { + if (s.color) return s.color; + var i = 0; + (DATA.categories || []).forEach(function (c, idx) { + if (c.id === s.cat) i = idx; + }); + return CAT_COLORS[i % CAT_COLORS.length]; + } + function endTime(start, minutes) { + if (!minutes) return ""; + var p = start.split(":"), + t = +p[0] * 60 + +p[1] + minutes; + return ( + String(Math.floor(t / 60) % 24).padStart(2, "0") + + ":" + + String(t % 60).padStart(2, "0") + ); + } + function productsWith(sid) { + return DATA.products.filter(function (p) { + return p.kind === "lessons" && p.services.indexOf(sid) !== -1; + }); + } + + function renderTop(active) { + var h = + '

Scegli come praticare

' + + (active === "calendar" + ? "Parti dall'orario: scegli una classe e vedi con quali pacchetti puoi frequentarla." + : "Pacchetti con la tua classe fissa, ingressi flessibili, una lezione singola o un regalo.") + + "

"; + var u = DATA.user || {}; + if (u.packages && u.packages.length) { + h += + '
I tuoi pacchetti attivi' + + u.packages + .slice(0, 3) + .map(function (k) { + return ( + "
" + + esc(k.title) + + "" + + (k.pending + ? "in attesa di pagamento" + : (k.left !== null + ? k.left + " lezioni" + : "") + + (k.expire + ? " · fino al " + fmtDate(k.expire) + : "")) + + "
" + ); + }) + .join("") + + "
"; + } + h += "
"; + if (u.membershipRequired && !u.hasMembership) { + h += + '
Per frequentare le lezioni serve la tessera associativa valida.' + + (u.membershipProduct + ? ' Acquista la tessera' + : " Chiedi in segreteria.") + + "
"; + } + var hasCal = Object.keys(DATA.services).some(function (k) { + return DATA.services[k].occ.length > 0; + }); + if (hasCal) { + h += + '
' + + '' + + '
'; + } + return h; + } + + function catSelect() { + if (!DATA.categories || DATA.categories.length < 2) return ""; + return ( + '" + ); + } + + function productCard(p, fromSvc) { + var min = Math.min.apply( + null, + p.variants.map(function (v) { + return v.price; + }), + ); + return ( + '
" + + '' + + esc(p.title) + + "" + + (p.subtitle + ? '' + esc(p.subtitle) + "" + : "") + + '' + + esc(ruleLine(p)) + + "" + + '' + + (p.variants.length > 1 ? "da " : "") + + euro(min) + + "" + ); + } + + function renderCatalog() { + var h = renderTop("products"); + var present = GROUPS.filter(function (g) { + return DATA.products.some(function (p) { + return p.group === g[0]; + }); + }); + h += + '"; + + var list = DATA.products.filter(function (p) { + if (S.filter && p.group !== S.filter) return false; + if ( + S.cat && + p.kind === "lessons" && + p.cats.indexOf(S.cat) === -1 + ) + return false; + if (S.cat && p.kind !== "lessons" && S.filter === "") + return false; + return true; + }); + if (!DATA.products.length) + return ( + h + + '
Al momento non ci sono prodotti in vendita.
' + ); + if (!list.length) + return ( + h + + '
Nessun prodotto con questi filtri.
' + ); + return ( + h + + '
' + + list + .map(function (p) { + return productCard(p); + }) + .join("") + + "
" + ); + } + + /* Orario settimanale: le classi ricavate dalla prossima lezione in calendario */ + function renderCalendar() { + var h = renderTop("calendar"); + h += + '
' + + catSelect() + + 'Tocca una classe per vedere come frequentarla
'; + + var cols = {}; + DAY_ORDER.forEach(function (d) { + cols[d] = []; + }); + Object.keys(DATA.services).forEach(function (k) { + var s = DATA.services[k], + sid = +k; + if ( + !s.occ.length || + (S.cat && s.cat !== S.cat) || + !productsWith(sid).length + ) + return; + var o = s.occ[0], + p = o.date.split("-"); + var wd = new Date(+p[0], +p[1] - 1, +p[2]).getDay(); + cols[wd].push({ sid: sid, s: s, o: o }); + }); + var days = DAY_ORDER.filter(function (d) { + return cols[d].length || (d >= 1 && d <= 5); + }); + if ( + !days.some(function (d) { + return cols[d].length; + }) + ) { + return ( + h + + '
Nessuna classe in calendario' + + (S.cat ? " per questa disciplina" : "") + + ".
" + ); + } + + h += '
'; + days.forEach(function (d) { + cols[d].sort(function (a, b) { + return a.o.time.localeCompare(b.o.time); + }); + h += + '
' + + DAYS[d] + + "
"; + if (!cols[d].length) h += '
—
'; + cols[d].forEach(function (it) { + var b = seatsBadge(it.o), + sel = S.cls === it.sid, + col = catColor(it.s); + var end = endTime(it.o.time, it.s.minutes); + h += + '"; + }); + h += "
"; + }); + h += "
"; + + if (S.cls && DATA.services[S.cls]) { + var s = DATA.services[S.cls], + list = productsWith(S.cls); + h += + '
' + + '
' + + esc(s.name) + + " · " + + esc(s.occ[0].label.split(" · ")[0].split(" ")[0]) + + " " + + esc(s.occ[0].time) + + "
" + + '
Prossime lezioni: ' + + s.occ + .slice(0, 3) + .map(function (o) { + return esc(o.label.replace(/^\S+\s/, "")); + }) + .join(" · ") + + "
" + + '
' + + '

' + + (list.length === 1 + ? "Puoi frequentarla con questo prodotto:" + : "Puoi frequentarla con questi prodotti:") + + "

" + + '
' + + list + .map(function (p) { + return productCard(p, S.cls); + }) + .join("") + + "
"; + } + return h; + } + + function renderProduct(p, v) { + var imgs = []; + if (p.cover) imgs.push(p.cover); + (p.gallery || []).forEach(function (g) { + if (imgs.indexOf(g) === -1) imgs.push(g); + }); + var cur = imgs[S.img] || imgs[0]; + + var h = + '
'; + h += cur + ? '' + : '"; + if (imgs.length > 1) { + h += + '
' + + imgs + .map(function (src, i) { + return ( + '' + ); + }) + .join("") + + "
"; + } + if (p.pros.length) { + h += + '

Vantaggi

' + + p.pros + .map(function (t) { + return ( + '
' + + esc(t) + + "
" + ); + }) + .join("") + + "
"; + } + if (p.cons.length) { + h += + '

Da considerare

' + + p.cons + .map(function (t) { + return ( + '
' + + esc(t) + + "
" + ); + }) + .join("") + + "
"; + } + h += '
'; + if (p.badge) + h += + '' + + esc(p.badge) + + ""; + h += '

' + esc(p.title) + "

"; + if (p.subtitle) + h += '

' + esc(p.subtitle) + "

"; + if (p.description) + h += '
' + p.description + "
"; + if (p.kind === "lessons" && p.services.length) { + h += + '

' + + (p.mode === "fixed" + ? "Classi tra cui scegliere" + : "Vale per queste classi") + + '

' + + p.services + .map(function (sid) { + var s = svc(sid); + return s + ? '' + + esc( + s.name + (s.day ? " · " + s.day : ""), + ) + + "" + : ""; + }) + .join("") + + "
" + + (p.weekly + ? '
Puoi prenotare al massimo ' + + p.weekly + + " lezioni a settimana.
" + : "") + + (p.maxres !== null && p.mode !== "single" + ? '
Recuperi inclusi: ' + + p.maxres + + ".
" + : "") + + "
"; + } + if (p.suitable || p.requirements) { + h += + '
' + + (p.suitable + ? "
Per chi è" + esc(p.suitable) + "
" + : "") + + (p.requirements + ? "
Cosa serve" + + esc(p.requirements) + + "
" + : "") + + "
"; + } + h += + '

' + + (p.variants.length > 1 ? "Scegli l'opzione" : "Prezzo") + + '

'; + p.variants.forEach(function (x) { + var sel = v && x.id === v.id; + h += + '"; + }); + h += "
"; + + var blocked = p.blocked === "used"; + h += buyBar( + v, + blocked + ? '' + : '', + ); + if (blocked) + h += + '

Questo prodotto si può acquistare una sola volta e l\'hai già utilizzato.

'; + return h; + } + + function buyBar(v, button) { + return ( + '
' + + esc(v ? v.label : "") + + '' + + (v ? euro(v.price) : "") + + "
" + + button + + "
" + ); + } + + function renderChoose(p, v) { + var h = + '
'; + if (p.mode === "fixed") { + var slots = p.slots || 1; + h += + '

' + + (slots === 2 + ? "Scegli le tue 2 classi" + : "Scegli la tua classe") + + '

' + + (slots === 1 + ? "Sarà il tuo posto fisso ogni settimana." + : "Saranno i tuoi due posti fissi ogni settimana.") + + "

"; + h += + '' + + S.picked.length + + " di " + + slots + + (slots === 1 ? " scelta" : " scelte") + + ""; + p.services.forEach(function (sid) { + var s = svc(sid); + if (!s) return; + var seat = fixedSeats(sid, p, v), + sel = S.picked.indexOf(sid) !== -1; + h += + '"; + }); + h += + '
Dopo l\'acquisto la scuola ti conferma la data della prima lezione e prenota per te tutte le altre, ogni settimana.
'; + } + if (p.mode === "single") { + var list = singleOccurrences(p); + h += + '

Scegli la lezione

Lezioni delle prossime settimane. Il posto si prenota quando completi l\'acquisto.

'; + if (!list.length) + h += + '
Al momento non ci sono lezioni prenotabili per questo prodotto.
'; + list.forEach(function (it) { + var b = seatsBadge(it.o), + sel = S.occ === it.o.id; + h += + '"; + }); + } + if (p.mode === "voucher") { + h += + '

A chi lo regali?

Il buono arriva via email con un codice da usare nel negozio della scuola.

' + + '
' + + '
' + + '
Metti la tua se preferisci consegnarlo di persona.
' + + '
"; + } + h += "
"; + h += buyBar( + v, + '', + ); + return h; + } + + function view() { + var hash = decodeURIComponent( + (location.hash || "").replace(/^#\/?/, ""), + ); + var parts = hash.split("/"); + if (parts[0] === "orario") return { name: "calendar" }; + var p = parts[0] ? bySlug(parts[0]) : null; + if (!p) return { name: "catalog" }; + return { + name: + parts[1] === "scegli" && + needsChoose(p) && + p.blocked !== "used" + ? "choose" + : "product", + p: p, + }; + } + + function render() { + var vw = view(), + html; + if (vw.name === "catalog") { + S.from = ""; + html = renderCatalog(); + } else if (vw.name === "calendar") { + S.from = "calendar"; + html = renderCalendar(); + } else { + if (S.pid !== vw.p.id) { + S.pid = vw.p.id; + S.vid = vw.p.variants[0].id; + S.picked = []; + S.occ = null; + S.img = 0; + // Arrivo dall'orario: preseleziona la classe scelta + if (S.prefSvc && vw.p.services.indexOf(S.prefSvc) !== -1) { + if ( + vw.p.mode === "fixed" && + fixedSeats(S.prefSvc, vw.p, variant(vw.p)).ok + ) + S.picked = [S.prefSvc]; + if (vw.p.mode === "single" && svc(S.prefSvc)) { + var free = svc(S.prefSvc).occ.filter(function (o) { + return seatsBadge(o).ok; + })[0]; + if (free) S.occ = free.id; + } + } + S.prefSvc = 0; + } + var v = variant(vw.p); + html = + vw.name === "choose" + ? renderChoose(vw.p, v) + : renderProduct(vw.p, v); + } + root.innerHTML = html; + var key = vw.name + (vw.p ? vw.p.id : ""); + if (lastView !== key) { + lastView = key; + var top = + root.getBoundingClientRect().top + window.pageYOffset - 90; + window.scrollTo({ top: Math.max(0, top) }); + } + } + + function go(hash) { + if (location.hash === hash) render(); + else location.hash = hash; + } + + /* ---------------- azioni ---------------- */ + var actions = { + filter: function (id) { + S.filter = id || ""; + render(); + }, + open: function (id, el) { + var p = byId(+id); + if (!p) return; + S.prefSvc = + el && el.getAttribute("data-svc") + ? +el.getAttribute("data-svc") + : 0; + S.pid = null; // nuova apertura: riparte dalle scelte predefinite + go("#/" + encodeURIComponent(p.slug)); + }, + home: function () { + go(S.from === "calendar" ? "#/orario" : "#/"); + }, + tab: function (id) { + go(id === "calendar" ? "#/orario" : "#/"); + }, + cls: function (id) { + S.cls = S.cls === +id ? 0 : +id; + render(); + var panel = document.getElementById("ys-calpanel"); + if (panel && panel.scrollIntoView) + panel.scrollIntoView({ + behavior: "smooth", + block: "nearest", + }); + }, + toProduct: function () { + var p = prod(); + if (p) go("#/" + encodeURIComponent(p.slug)); + }, + img: function (i) { + S.img = +i; + render(); + }, + variant: function (id) { + S.vid = +id; + var p = prod(), + v = variant(p); + if (p && p.mode === "fixed") + S.picked = S.picked.filter(function (sid) { + return fixedSeats(sid, p, v).ok; + }); + render(); + }, + next: function () { + var p = prod(); + if (!p || p.blocked === "used") return; + if (needsChoose(p)) + go("#/" + encodeURIComponent(p.slug) + "/scegli"); + else actions.checkout(); + }, + pickClass: function (id) { + var p = prod(), + sid = +id, + slots = p.slots || 1, + arr = S.picked.slice(), + i = arr.indexOf(sid); + if (i !== -1) arr.splice(i, 1); + else if (slots === 1) arr = [sid]; + else if (arr.length < slots) arr.push(sid); + else arr = [arr[1], sid]; + S.picked = arr; + render(); + }, + pickOcc: function (id) { + S.occ = +id; + render(); + }, + checkout: function () { + var p = prod(), + v = variant(p); + if (!p || !v || !chooseValid(p) || p.blocked === "used") return; + var sel = { + product: p, + variant: v, + idvariant: v.id, + services: p.mode === "fixed" ? S.picked.slice() : [], + idschedule: p.mode === "single" ? S.occ : null, + recipient: + p.mode === "voucher" + ? { + name: S.rName.trim(), + email: S.rEmail.trim(), + message: S.rMsg.trim(), + } + : null, + }; + if (typeof opts.onCheckout === "function") opts.onCheckout(sel); + }, + }; + + root.addEventListener("click", function (ev) { + var el = ev.target.closest("[data-act]"); + if ( + !el || + el.disabled || + !root.contains(el) || + el.tagName === "SELECT" + ) + return; + var fn = actions[el.getAttribute("data-act")]; + if (fn) fn(el.getAttribute("data-id"), el); + }); + root.addEventListener("change", function (ev) { + if (ev.target.getAttribute("data-act") === "cat") { + S.cat = +ev.target.value; + S.cls = 0; + render(); + } + }); + root.addEventListener("input", function (ev) { + var f = ev.target.getAttribute("data-field"); + if (!f) return; + S[f] = ev.target.value; + var btn = document.getElementById("ys-go"); + if (btn) btn.disabled = !chooseValid(prod()); + }); + window.addEventListener("hashchange", render); + render(); + } + + window.YBShop = { mount: mount }; + + // Webapp: monta il negozio e invia le scelte a shop_checkout.php + document.addEventListener("DOMContentLoaded", function () { + var root = document.getElementById("shop"); + if (!root || !window.YB_SHOP) return; + mount(root, window.YB_SHOP, { + onCheckout: function (sel) { + var f = document.getElementById("checkout-form"); + document.getElementById("f-variant").value = sel.idvariant; + document.getElementById("f-services").value = + sel.services.join(","); + document.getElementById("f-schedule").value = + sel.idschedule || ""; + document.getElementById("f-rname").value = sel.recipient + ? sel.recipient.name + : ""; + document.getElementById("f-remail").value = sel.recipient + ? sel.recipient.email + : ""; + document.getElementById("f-rmsg").value = sel.recipient + ? sel.recipient.message + : ""; + f.submit(); + }, + }); + }); +})(); diff --git a/public/class/SchoolScope.php b/public/class/SchoolScope.php index beffb89..1a9d59e 100644 --- a/public/class/SchoolScope.php +++ b/public/class/SchoolScope.php @@ -32,6 +32,7 @@ class SchoolScope 'orderbook' => 'idorderbook', 'employee' => 'idemployee', 'dayoff' => 'iddayoff', + 'expiryparameter' => 'idexpiryparameter', 'certificateuserprofile' => 'idcertificateuserprofile', 'events' => 'id', 'event_bookings' => 'id', diff --git a/public/class/SchoolSetup.php b/public/class/SchoolSetup.php new file mode 100644 index 0000000..544ff7a --- /dev/null +++ b/public/class/SchoolSetup.php @@ -0,0 +1,303 @@ + ['La tua scuola', 'Come ti presenti ad allieve e insegnanti'], + 'classes' => ['Classi e calendario', 'Cosa si può prenotare e quando'], + 'sell' => ['Vendita', 'Cosa vendi e come ti pagano'], + 'test' => ['Prova finale', 'Fai un giro completo come farà un\'allieva'], + ]; + + /** Stato manuale salvato: ['done' => [key => data], 'skip' => [key => data], 'progress' => 'x/y'] */ + public static function state(int $idschool): array + { + $raw = (string) SchoolSettings::get('setup_state', '', $idschool); + $s = json_decode($raw, true); + return is_array($s) ? $s + ['done' => [], 'skip' => []] : ['done' => [], 'skip' => []]; + } + + public static function saveState(int $idschool, array $state): void + { + SchoolSettings::save(['setup_state' => json_encode($state, JSON_UNESCAPED_UNICODE)], $idschool); + } + + public static function completed(int $idschool): bool + { + return (string) SchoolSettings::get('setup_completed_at', '', $idschool) !== ''; + } + + /** Elenco dei passi con stato calcolato */ + public static function steps(int $idschool, int $userId): array + { + $pdo = DBHandlerSelect::getInstance()->getConnection(); + $one = function (string $sql, array $args) use ($pdo) { + $st = $pdo->prepare($sql); + $st->execute($args); + return $st->fetchColumn(); + }; + $state = self::state($idschool); + + $st = $pdo->prepare("SELECT * FROM schools WHERE idschool = ?"); + $st->execute([$idschool]); + $sc = $st->fetch(PDO::FETCH_ASSOC) ?: []; + $filled = fn($k) => trim((string) ($sc[$k] ?? '')) !== ''; + + $teachers = (int) $one("SELECT COUNT(*) FROM employee WHERE idschool = ? AND active = 'Y'", [$idschool]); + $classes = (int) $one("SELECT COUNT(*) FROM service WHERE idschool = ?", [$idschool]); + $future = (int) $one("SELECT COUNT(*) FROM serviceschedule WHERE idschool = ? AND dateschedule > NOW()", [$idschool]); + $dayoffs = (int) $one("SELECT COUNT(*) FROM dayoff WHERE idschool = ? AND dayoffdate >= CURDATE()", [$idschool]); + $rules = (int) $one("SELECT COUNT(*) FROM expiryparameter WHERE idschool = ?", [$idschool]); + $products = (int) $one( + "SELECT COUNT(*) FROM products p WHERE p.idschool = ? AND p.active = 'Y' + AND EXISTS (SELECT 1 FROM product_variants v WHERE v.idproduct = p.idproduct AND v.active = 'Y')", + [$idschool] + ); + $bankOk = SchoolSettings::get('bank_enabled', 'N', $idschool) === 'Y' && trim((string) SchoolSettings::get('bank_iban', '', $idschool)) !== ''; + $cardOk = SchoolSettings::get('stripe_charges_enabled', 'N', $idschool) === 'Y'; + $shopOn = SchoolSettings::get('shop_enabled', 'N', $idschool) === 'Y'; + $testOrder = (int) $one("SELECT COUNT(*) FROM orderbook WHERE idschool = ? AND iduser = ? AND idproduct IS NOT NULL", [$idschool, $userId]); + $testDone = (int) $one("SELECT COUNT(*) FROM orderbook WHERE idschool = ? AND iduser = ? AND idproduct IS NOT NULL AND payment_status IN ('paid', 'cancelled')", [$idschool, $userId]); + $students = (int) $one("SELECT COUNT(*) FROM school_user WHERE idschool = ? AND school_role = 'student' AND active = 'Y' AND user_id <> ?", [$idschool, $userId]); + + $sub = null; + if (is_file(__DIR__ . '/PlatformBilling.php')) { + require_once __DIR__ . '/PlatformBilling.php'; + try { + $row = PlatformBilling::school($idschool); + $sub = $row ? PlatformBilling::state($row) : null; + } catch (Throwable $ex) { + $sub = null; + } + } + + $steps = [ + // ---------------- La scuola + [ + 'key' => 'profile', + 'phase' => 'school', + 'required' => true, + 'title' => 'Dati della scuola', + 'text' => 'Nome, email, indirizzo e città: compaiono nelle email alle allieve, nella pagina pubblica e nelle ricevute.', + 'url' => 'optionsschool.php?tab=profile', + 'cta' => 'Compila i dati', + 'done' => $filled('name') && $filled('email') && $filled('address') && $filled('city'), + 'detail' => $filled('email') ? '' : 'Manca l\'email della scuola: serve come mittente delle email.' + ], + [ + 'key' => 'public', + 'phase' => 'school', + 'required' => false, + 'title' => 'Logo e presentazione', + 'text' => 'Il logo appare in alto nell\'app; slogan e descrizione nella pagina della scuola.', + 'url' => 'optionsschool.php?tab=public', + 'cta' => 'Carica il logo', + 'done' => $filled('logo') && ($filled('short_description') || $filled('description')) + ], + [ + 'key' => 'look', + 'phase' => 'school', + 'required' => false, + 'manual' => true, + 'title' => 'Colori dell\'app', + 'text' => 'Scegli i colori della tua scuola. Se non li tocchi resta il tema YogiBook.', + 'url' => 'optionsschool.php?tab=theme', + 'cta' => 'Scegli i colori', + 'done' => false + ], + [ + 'key' => 'teachers', + 'phase' => 'school', + 'required' => true, + 'title' => 'Insegnanti', + 'text' => 'Aggiungi chi insegna: servono per assegnare le classi. Puoi inserire anche te stessa.', + 'url' => 'insegnanti.php', + 'cta' => 'Aggiungi insegnanti', + 'done' => $teachers > 0, + 'detail' => $teachers ? $teachers . ' attivi' : '' + ], + + // ---------------- Classi e calendario + [ + 'key' => 'classes', + 'phase' => 'classes', + 'required' => true, + 'title' => 'Classi', + 'text' => 'Crea le categorie (es. Hatha, Aerial) e le classi settimanali con giorno, orario, durata e posti.', + 'url' => 'admin-services.php', + 'cta' => 'Crea le classi', + 'done' => $classes > 0, + 'detail' => $classes ? $classes . ' classi' : '' + ], + [ + 'key' => 'calendar', + 'phase' => 'classes', + 'required' => true, + 'title' => 'Calendario delle lezioni', + 'text' => 'Genera le lezioni in calendario per le prossime settimane: sono quelle che le allieve prenotano.', + 'url' => 'admin-services.php', + 'cta' => 'Programma le lezioni', + 'done' => $future > 0, + 'detail' => $future ? $future . ' lezioni in calendario' : '' + ], + [ + 'key' => 'dayoff', + 'phase' => 'classes', + 'required' => false, + 'title' => 'Giorni di chiusura', + 'text' => 'Festività e chiusure: in quei giorni non si prenota e i pacchetti non scalano lezioni.', + 'url' => 'dayoff.php', + 'cta' => 'Aggiungi chiusure', + 'done' => $dayoffs > 0 + ], + [ + 'key' => 'booking', + 'phase' => 'classes', + 'required' => true, + 'manual' => true, + 'title' => 'Regole di prenotazione', + 'text' => 'Lista d\'attesa, insegnante visibile, ore minime per annullare, avviso per le allieve. Controllale e segna il passo come fatto.', + 'url' => 'optionsschool.php?tab=booking', + 'cta' => 'Controlla le regole', + 'done' => false + ], + [ + 'key' => 'packages', + 'phase' => 'classes', + 'required' => true, + 'title' => 'Scadenza e recuperi dei pacchetti', + 'text' => 'Per ogni numero di lezioni: dopo quante lezioni scade il pacchetto e quanti recuperi sono ammessi.', + 'url' => 'package_rules.php', + 'cta' => 'Imposta le regole', + 'done' => $rules > 0, + 'detail' => $rules ? $rules . ' regole' : '' + ], + + // ---------------- Vendita + [ + 'key' => 'products', + 'phase' => 'sell', + 'required' => true, + 'title' => 'Prodotti', + 'text' => 'Cosa vendi: pacchetti a classe fissa, carnet, lezione di prova, tessera, buoni regalo. Con foto, prezzi e opzioni.', + 'url' => 'products.php', + 'cta' => 'Crea i prodotti', + 'done' => $products > 0, + 'detail' => $products ? $products . ' in vendita' : '' + ], + [ + 'key' => 'payments', + 'phase' => 'sell', + 'required' => true, + 'title' => 'Pagamenti', + 'text' => 'Attiva il bonifico (intestatario e IBAN) e, quando disponibile, la carta. Imposta anche le condizioni di acquisto.', + 'url' => 'optionsschool.php?tab=shop', + 'cta' => 'Configura i pagamenti', + 'done' => $bankOk || $cardOk, + 'detail' => trim(($bankOk ? 'Bonifico' : '') . ($bankOk && $cardOk ? ' · ' : '') . ($cardOk ? 'Carta' : '')) + ], + [ + 'key' => 'shop', + 'phase' => 'sell', + 'required' => true, + 'title' => 'Apri il negozio', + 'text' => 'Accendi "Negozio attivo": da quel momento le allieve possono acquistare dall\'app.', + 'url' => 'optionsschool.php?tab=shop', + 'cta' => 'Attiva il negozio', + 'done' => $shopOn + ], + [ + 'key' => 'subscription', + 'phase' => 'sell', + 'required' => false, + 'title' => 'Abbonamento YogiBook', + 'text' => 'Controlla il tuo piano e la scadenza della prova.', + 'url' => 'subscription.php', + 'cta' => 'Vedi l\'abbonamento', + 'done' => $sub !== null && in_array($sub['code'], ['active', 'expiring', 'exempt'], true), + 'detail' => $sub ? $sub['label'] . ($sub['ends_on'] ? ' fino al ' . date('d/m/Y', strtotime($sub['ends_on'])) : '') : '' + ], + + // ---------------- Prova finale + [ + 'key' => 'test_buy', + 'phase' => 'test', + 'required' => true, + 'title' => 'Acquista come un\'allieva', + 'text' => 'Dal selettore Vista in alto nel menu passa a "Allievo", apri il Negozio e compra un prodotto con bonifico. Controlla riepilogo, causale e pagina di conferma.', + 'url' => 'shop.php', + 'cta' => 'Apri il negozio', + 'done' => $testOrder > 0 + ], + [ + 'key' => 'test_confirm', + 'phase' => 'test', + 'required' => true, + 'title' => 'Gestisci l\'ordine di prova', + 'text' => 'Torna alla vista "Scuola", apri Ordini: segna il pagamento come ricevuto (e propagalo se è a classe fissa) oppure annullalo.', + 'url' => 'school_orders.php', + 'cta' => 'Apri gli ordini', + 'done' => $testDone > 0 + ], + [ + 'key' => 'test_book', + 'phase' => 'test', + 'required' => false, + 'manual' => true, + 'title' => 'Prenota e annulla una lezione', + 'text' => 'Sempre come allieva, prenota una lezione dal pannello Prenotazioni e poi annullala: verifichi posti e regole di cancellazione.', + 'url' => 'userpanel.php', + 'cta' => 'Apri le prenotazioni', + 'done' => false + ], + [ + 'key' => 'invite', + 'phase' => 'test', + 'required' => false, + 'manual' => true, + 'title' => 'Invita le tue allieve', + 'text' => 'Comunica alle allieve l\'indirizzo di YogiBook per registrarsi e scegli tu quando aprire il negozio a tutte.', + 'url' => '', + 'cta' => '', + 'done' => $students > 0, + 'detail' => $students ? $students . ' allieve iscritte' : '' + ], + ]; + + foreach ($steps as &$s) { + $s += ['manual' => false, 'detail' => '']; + $s['auto'] = $s['done']; + $s['done'] = $s['done'] || isset($state['done'][$s['key']]); + $s['skipped'] = !$s['done'] && !$s['required'] && isset($state['skip'][$s['key']]); + } + unset($s); + return $steps; + } + + /** [fatti (o saltati), totale, obbligatori mancanti] */ + public static function progress(array $steps): array + { + $done = 0; + $missing = 0; + foreach ($steps as $s) { + if ($s['done'] || $s['skipped']) { + $done++; + } elseif ($s['required']) { + $missing++; + } + } + return [$done, count($steps), $missing]; + } +} diff --git a/public/class/ShopService.php b/public/class/ShopService.php new file mode 100644 index 0000000..e26b8b3 --- /dev/null +++ b/public/class/ShopService.php @@ -0,0 +1,976 @@ + 'gennaio', 'febbraio', 'marzo', 'aprile', 'maggio', 'giugno', 'luglio', 'agosto', 'settembre', 'ottobre', 'novembre', 'dicembre']; + + /** + * Catalogo completo, pronto per json_encode (lo stesso formato servirà all'API WordPress). + * + * @param int $idschool + * @param int|null $userId allieva loggata (per prova già usata, tessera, pacchetti attivi) + * @param bool $onlineOnly true = solo prodotti "acquistabili online" + */ + public static function catalog(int $idschool, ?int $userId = null, bool $onlineOnly = true): array + { + $pdo = self::pdo(); + + // ---- Prodotti e opzioni + $st = $pdo->prepare( + "SELECT * FROM products WHERE idschool = ? AND active = 'Y'" . ($onlineOnly ? " AND visible_online = 'Y'" : "") . " + ORDER BY FIELD(kind, 'lessons', 'membership', 'voucher'), sort_order, title" + ); + $st->execute([$idschool]); + $rows = $st->fetchAll(PDO::FETCH_ASSOC); + + $variantsBy = []; + $st = $pdo->prepare("SELECT * FROM product_variants WHERE idschool = ? AND active = 'Y' ORDER BY sort_order, idvariant"); + $st->execute([$idschool]); + foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $v) { + $variantsBy[(int) $v['idproduct']][] = $v; + } + + $linksBy = []; + $st = $pdo->prepare("SELECT idproduct, idservice, idservicecategory FROM product_services WHERE idschool = ?"); + $st->execute([$idschool]); + foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $l) { + $linksBy[(int) $l['idproduct']][] = $l; + } + + $galleryBy = []; + $st = $pdo->prepare("SELECT idproduct, filename FROM product_images WHERE idschool = ? ORDER BY sort_order, idimage"); + $st->execute([$idschool]); + foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $g) { + $galleryBy[(int) $g['idproduct']][] = $g['filename']; + } + + $variantLabel = []; + $st = $pdo->prepare("SELECT v.idvariant, v.label, p.title FROM product_variants v JOIN products p ON p.idproduct = v.idproduct WHERE v.idschool = ?"); + $st->execute([$idschool]); + foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $r) { + $variantLabel[(int) $r['idvariant']] = $r['title'] . ' · ' . $r['label']; + } + + // ---- Classi della scuola + $showTeacher = SchoolSettings::get('show_teacher', 'N', $idschool) === 'Y'; + $st = $pdo->prepare( + "SELECT s.idservice, s.servicename, s.day, s.time, s.category, s.maxcapacity, s.colorclass, s.classduration, + TRIM(CONCAT(COALESCE(em.nameemployee, ''), ' ', COALESCE(em.surnameemployee, ''))) AS teacher + FROM service s + LEFT JOIN employee em ON em.idemployee = s.idteacher AND em.idschool = s.idschool + WHERE s.idschool = ?" + ); + $st->execute([$idschool]); + $servicesAll = []; + $byCategory = []; + foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $s) { + $servicesAll[(int) $s['idservice']] = $s; + $byCategory[(int) $s['category']][] = (int) $s['idservice']; + } + + $st = $pdo->prepare("SELECT idservicecategory, namecategory FROM servicecategory WHERE idschool = ? ORDER BY namecategory"); + $st->execute([$idschool]); + $catNames = []; + foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $c) { + $catNames[(int) $c['idservicecategory']] = $c['namecategory']; + } + + // ---- Situazione dell'allieva + $user = self::userContext($idschool, $userId); + + // ---- Costruzione prodotti + $products = []; + $usedSvcs = []; + $usedCats = []; + foreach ($rows as $p) { + $pid = (int) $p['idproduct']; + if (empty($variantsBy[$pid])) { + continue; // nessuna opzione attiva = non acquistabile + } + $svc = []; + foreach ($linksBy[$pid] ?? [] as $l) { + if (!empty($l['idservice']) && isset($servicesAll[(int) $l['idservice']])) { + $svc[] = (int) $l['idservice']; + } + if (!empty($l['idservicecategory'])) { + $svc = array_merge($svc, $byCategory[(int) $l['idservicecategory']] ?? []); + } + } + $svc = array_values(array_unique($svc)); + if ($p['kind'] === 'lessons' && !$svc) { + continue; // pacchetto senza classi: non vendibile + } + + $cats = []; + foreach ($svc as $sid) { + $cid = (int) $servicesAll[$sid]['category']; + if (isset($catNames[$cid])) { + $cats[$cid] = true; + } + } + $cats = array_keys($cats); + if ($p['kind'] === 'lessons') { + $usedSvcs = array_merge($usedSvcs, $svc); + $usedCats = array_merge($usedCats, $cats); + } + + $variants = []; + foreach ($variantsBy[$pid] as $v) { + $variants[] = [ + 'id' => (int) $v['idvariant'], + 'label' => $v['label'], + 'lessons' => $v['lessons'] !== null ? (int) $v['lessons'] : null, + 'price' => (float) $v['price'], + 'compare' => $v['compare_price'] !== null ? (float) $v['compare_price'] : null, + 'note' => $v['price_note'], + 'vmode' => $v['validity_mode'], + 'vvalue' => $v['validity_value'] !== null ? (int) $v['validity_value'] : null, + 'vunit' => $v['validity_unit'], + 'vstart' => $v['validity_start'], + 'target' => $v['target_idvariant'] !== null ? (int) $v['target_idvariant'] : null, + 'targetLabel' => $v['target_idvariant'] !== null ? ($variantLabel[(int) $v['target_idvariant']] ?? '') : '', + ]; + } + + $mode = $p['kind'] === 'lessons' ? $p['booking_mode'] : $p['kind']; + $products[] = [ + 'id' => $pid, + 'slug' => $p['slug'], + 'kind' => $p['kind'], + 'mode' => $mode, // fixed | free | single | membership | voucher + 'group' => self::group($p), // per i filtri del catalogo + 'slots' => (int) $p['fixed_slots'], + 'weekly' => $p['weekly_limit'] !== null ? (int) $p['weekly_limit'] : null, + 'maxres' => $p['max_reschedule'] !== null ? (int) $p['max_reschedule'] : null, + 'once' => $p['once_per_student'] === 'Y', + 'title' => $p['title'], + 'subtitle' => (string) $p['subtitle'], + 'badge' => (string) $p['badge'], + 'cover' => (string) $p['cover_image'], + 'gallery' => $galleryBy[$pid] ?? [], + 'description' => (string) $p['description'], // HTML già ripulito al salvataggio + 'suitable' => (string) $p['suitable_for'], + 'requirements' => (string) $p['requirements'], + 'pros' => self::lines($p['pros']), + 'cons' => self::lines($p['cons']), + 'services' => $svc, + 'cats' => $cats, + 'variants' => $variants, + 'blocked' => ($p['once_per_student'] === 'Y' && in_array($pid, $user['usedProducts'], true)) ? 'used' : null, + ]; + } + + // ---- Calendario e posti delle classi usate dai pacchetti + $services = self::servicesWithOccurrences($idschool, array_values(array_unique($usedSvcs)), $servicesAll, $showTeacher, $userId); + + // ---- Discipline (categorie) presenti nel catalogo + $categories = []; + foreach (array_unique($usedCats) as $cid) { + $categories[] = ['id' => $cid, 'name' => $catNames[$cid]]; + } + usort($categories, fn($a, $b) => strcasecmp($a['name'], $b['name'])); + + // ---- Date utili (tessere) + $seasonStart = max(1, min(12, (int) SchoolSettings::get('membership_season_start', 9, $idschool))); + $today = new DateTimeImmutable('today'); + $y = (int) $today->format('Y'); + $endYear = ((int) $today->format('n') >= $seasonStart) ? $y + 1 : $y; + $seasonEnd = (new DateTimeImmutable(sprintf('%04d-%02d-01', $endYear, $seasonStart)))->modify('-1 day'); + + // Prodotto tessera da proporre se serve + $user['membershipProduct'] = null; + foreach ($products as $p) { + if ($p['kind'] === 'membership') { + $user['membershipProduct'] = $p['id']; + break; + } + } + unset($user['usedProducts']); + + return [ + 'today' => $today->format('Y-m-d'), + 'yearEnd' => $y . '-12-31', + 'seasonEnd' => $seasonEnd->format('Y-m-d'), + 'singleDays' => self::SINGLE_DAYS, + 'products' => $products, + 'services' => (object) $services, + 'categories' => $categories, + 'user' => $user, + ]; + } + + /** Gruppo del catalogo: single | fixed | free | membership | voucher */ + public static function group(array $p): string + { + return $p['kind'] === 'lessons' ? (string) $p['booking_mode'] : (string) $p['kind']; + } + + /** + * Situazione dell'allieva nella scuola: prodotti "una volta" già acquistati, + * tessera valida, pacchetti attivi. + */ + public static function userContext(int $idschool, ?int $userId): array + { + $required = SchoolSettings::get('membership_required', 'N', $idschool) === 'Y'; + $ctx = [ + 'logged' => (bool) $userId, + 'membershipRequired' => $required, + 'hasMembership' => false, + 'membershipUntil' => null, + 'packages' => [], + 'usedProducts' => [], + ]; + if (!$userId) { + return $ctx; + } + $pdo = self::pdo(); + + $st = $pdo->prepare( + "SELECT DISTINCT idproduct FROM orderbook + WHERE iduser = ? AND idschool = ? AND idproduct IS NOT NULL + AND (payment_status IS NULL OR payment_status NOT IN ('cancelled', 'refunded'))" + ); + $st->execute([$userId, $idschool]); + $ctx['usedProducts'] = array_map('intval', $st->fetchAll(PDO::FETCH_COLUMN)); + + $st = $pdo->prepare( + "SELECT MAX(valid_to) FROM memberships + WHERE iduser = ? AND idschool = ? AND status = 'active' AND valid_from <= CURDATE() AND valid_to >= CURDATE()" + ); + $st->execute([$userId, $idschool]); + $until = $st->fetchColumn(); + $ctx['hasMembership'] = (bool) $until; + $ctx['membershipUntil'] = $until ?: null; + + // Pacchetti attivi: non scaduti e con lezioni rimaste + $st = $pdo->prepare( + "SELECT ob.idorderbook, ob.product_name, ob.nticket, ob.quantityclass, ob.expireon, ob.payment_status, + s.servicename, + (SELECT COUNT(*) FROM bookingclass b + WHERE b.idorder = ob.idorderbook AND b.idschool = ob.idschool + AND b.status <> 'cancelled' AND b.is_gift = 'N') AS used + FROM orderbook ob + LEFT JOIN service s ON s.idservice = ob.idservice + WHERE ob.iduser = ? AND ob.idschool = ? + AND (ob.expireon IS NULL OR ob.expireon >= CURDATE()) + AND (ob.payment_status IS NULL OR ob.payment_status NOT IN ('cancelled', 'refunded')) + ORDER BY ob.expireon IS NULL, ob.expireon" + ); + $st->execute([$userId, $idschool]); + foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $o) { + $tot = (int) $o['nticket'] > 0 ? (int) $o['nticket'] : (int) $o['quantityclass']; + $left = $tot > 0 ? max(0, $tot - (int) $o['used']) : null; + if ($left === 0) { + continue; + } + $ctx['packages'][] = [ + 'title' => (string) ($o['product_name'] ?: $o['servicename'] ?: 'Pacchetto'), + 'left' => $left, + 'expire' => $o['expireon'], + 'pending' => $o['payment_status'] === 'pending', + ]; + } + return $ctx; + } + + /** + * Lezioni future delle classi indicate, con posti liberi. + * @return array idservice => [name, day, teacher, cap, cat, occ => [[id, date, time, label, free, mine]]] + */ + public static function servicesWithOccurrences(int $idschool, array $ids, array $servicesAll, bool $showTeacher, ?int $userId = null): array + { + $out = []; + foreach ($ids as $sid) { + if (!isset($servicesAll[$sid])) { + continue; + } + $s = $servicesAll[$sid]; + $out[$sid] = [ + 'name' => $s['servicename'], + 'day' => trim($s['day'] . ' ' . $s['time']), + 'teacher' => $showTeacher ? trim((string) $s['teacher']) : '', + 'cap' => ($s['maxcapacity'] !== null && (int) $s['maxcapacity'] > 0) ? (int) $s['maxcapacity'] : null, + 'cat' => (int) $s['category'], + 'color' => preg_match('/^#[0-9a-fA-F]{6}$/', (string) ($s['colorclass'] ?? '')) ? strtolower($s['colorclass']) : null, + 'minutes' => (int) round((float) ($s['classduration'] ?? 0) * ((float) ($s['classduration'] ?? 0) <= 5 ? 60 : 1)), + 'occ' => [], + ]; + } + if (!$out) { + return $out; + } + + $ph = implode(',', array_fill(0, count($out), '?')); + $st = self::pdo()->prepare( + "SELECT ss.idserviceschedule, ss.idservice, ss.dateschedule, + (SELECT COUNT(*) FROM bookingclass b + WHERE b.idserviceschedule = ss.idserviceschedule AND b.idschool = ss.idschool + AND b.status IN ('booked', 'pending')) AS taken + " . ($userId ? ", (SELECT COUNT(*) FROM bookingclass b2 + WHERE b2.idserviceschedule = ss.idserviceschedule AND b2.idschool = ss.idschool + AND b2.iduser = ? AND b2.status <> 'cancelled') AS mine" : ", 0 AS mine") . " + FROM serviceschedule ss + WHERE ss.idschool = ? + AND ss.idservice IN ($ph) + AND ss.dateschedule > NOW() + AND ss.dateschedule < CURDATE() + INTERVAL " . (int) self::LOOKAHEAD_DAYS . " DAY + AND NOT EXISTS (SELECT 1 FROM dayoff d WHERE d.idschool = ss.idschool AND d.dayoffdate = DATE(ss.dateschedule)) + ORDER BY ss.dateschedule" + ); + $args = $userId ? [$userId, $idschool] : [$idschool]; + $st->execute(array_merge($args, array_keys($out))); + + foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $o) { + $sid = (int) $o['idservice']; + if (count($out[$sid]['occ']) >= self::MAX_OCCURRENCES) { + continue; + } + $ts = strtotime($o['dateschedule']); + $cap = $out[$sid]['cap']; + $out[$sid]['occ'][] = [ + 'id' => (int) $o['idserviceschedule'], + 'date' => date('Y-m-d', $ts), + 'time' => date('H:i', $ts), + 'label' => self::dateLabel($ts), + 'free' => $cap === null ? null : max(0, $cap - (int) $o['taken']), + 'mine' => (int) $o['mine'] > 0, + ]; + } + return $out; + } + + /** "Martedì 13 ottobre · 18:00" */ + public static function dateLabel(int $ts): string + { + return ucfirst(self::GIORNI[(int) date('w', $ts)]) . ' ' . date('j', $ts) . ' ' . self::MESI[(int) date('n', $ts)] . ' · ' . date('H:i', $ts); + } + + public static function lines(?string $t): array + { + return array_values(array_filter(array_map('trim', preg_split('/\r\n|\r|\n/', (string) $t)))); + } + + /* ================================================================== + * CHECKOUT + * ================================================================ */ + + /** Metodi di pagamento attivi per la scuola */ + public static function paymentMethods(int $idschool): array + { + $bank = SchoolSettings::get('bank_enabled', 'N', $idschool) === 'Y' + && trim((string) SchoolSettings::get('bank_holder', '', $idschool)) !== '' + && trim((string) SchoolSettings::get('bank_iban', '', $idschool)) !== ''; + // La carta arriverà con il collegamento Stripe Connect della scuola + $card = SchoolSettings::get('stripe_charges_enabled', 'N', $idschool) === 'Y' + && trim((string) SchoolSettings::get('stripe_account_id', '', $idschool)) !== ''; + return ['bank' => $bank, 'card' => $card]; + } + + /** + * Ricontrolla lato server la scelta arrivata dal negozio. + * $in: idvariant, services (array di idservice), idschedule, recipient_name, recipient_email, recipient_message + * @return array product, variant, services, schedule, recipient + * @throws RuntimeException con messaggio per l'allieva + */ + public static function selection(int $idschool, int $userId, array $in): array + { + $pdo = self::pdo(); + $st = $pdo->prepare( + "SELECT v.*, p.kind, p.title, p.booking_mode, p.fixed_slots, p.weekly_limit, p.max_reschedule, + p.once_per_student, p.active AS p_active, p.visible_online, p.slug + FROM product_variants v + JOIN products p ON p.idproduct = v.idproduct AND p.idschool = v.idschool + WHERE v.idvariant = ? AND v.idschool = ?" + ); + $st->execute([(int) ($in['idvariant'] ?? 0), $idschool]); + $row = $st->fetch(PDO::FETCH_ASSOC); + if (!$row || $row['active'] !== 'Y' || $row['p_active'] !== 'Y' || $row['visible_online'] !== 'Y') { + throw new RuntimeException('Questo prodotto non è più disponibile.'); + } + $pid = (int) $row['idproduct']; + $mode = $row['kind'] === 'lessons' ? $row['booking_mode'] : $row['kind']; + + if ($row['once_per_student'] === 'Y') { + $st = $pdo->prepare( + "SELECT 1 FROM orderbook WHERE iduser = ? AND idschool = ? AND idproduct = ? + AND (payment_status IS NULL OR payment_status NOT IN ('cancelled', 'refunded')) LIMIT 1" + ); + $st->execute([$userId, $idschool, $pid]); + if ($st->fetchColumn()) { + throw new RuntimeException('Hai già utilizzato questo prodotto: si può acquistare una sola volta.'); + } + } + + $allowed = self::productServiceIds($idschool, $pid); + $sel = [ + 'product' => $row, + 'mode' => $mode, + 'variant' => $row, + 'services' => [], + 'schedule' => null, + 'recipient' => null, + ]; + + if ($mode === 'fixed') { + $slots = (int) $row['fixed_slots'] === 2 ? 2 : 1; + $ids = array_values(array_unique(array_filter(array_map('intval', (array) ($in['services'] ?? []))))); + if (count($ids) !== $slots) { + throw new RuntimeException($slots === 2 ? 'Scegli le tue due classi.' : 'Scegli la tua classe.'); + } + $weeks = $row['lessons'] ? (int) ceil((int) $row['lessons'] / $slots) : 8; + foreach ($ids as $sid) { + if (!in_array($sid, $allowed, true)) { + throw new RuntimeException('Una delle classi scelte non è inclusa in questo prodotto.'); + } + $free = self::fixedFree($idschool, $sid, $weeks); + if ($free === -1) { + throw new RuntimeException('Una delle classi scelte non ha lezioni in calendario.'); + } + if ($free === 0) { + throw new RuntimeException('Una delle classi scelte è al completo. Torna indietro e scegline un\'altra.'); + } + } + $sel['services'] = $ids; + } + + if ($mode === 'single') { + $st = $pdo->prepare( + "SELECT ss.*, s.servicename, s.maxcapacity FROM serviceschedule ss + JOIN service s ON s.idservice = ss.idservice + WHERE ss.idserviceschedule = ? AND ss.idschool = ? AND ss.dateschedule > NOW()" + ); + $st->execute([(int) ($in['idschedule'] ?? 0), $idschool]); + $sch = $st->fetch(PDO::FETCH_ASSOC); + if (!$sch || !in_array((int) $sch['idservice'], $allowed, true)) { + throw new RuntimeException('La lezione scelta non è più disponibile.'); + } + $st = $pdo->prepare("SELECT 1 FROM bookingclass WHERE idserviceschedule = ? AND iduser = ? AND idschool = ? AND status <> 'cancelled' LIMIT 1"); + $st->execute([(int) $sch['idserviceschedule'], $userId, $idschool]); + if ($st->fetchColumn()) { + throw new RuntimeException('Sei già iscritta a questa lezione.'); + } + if ((int) $sch['maxcapacity'] > 0 && self::occupied($idschool, (int) $sch['idserviceschedule']) >= (int) $sch['maxcapacity']) { + throw new RuntimeException('La lezione scelta è al completo. Torna indietro e scegli un\'altra data.'); + } + $sel['schedule'] = $sch; + } + + if ($mode === 'voucher') { + $name = trim((string) ($in['recipient_name'] ?? '')); + $email = trim((string) ($in['recipient_email'] ?? '')); + if ($name === '' || !filter_var($email, FILTER_VALIDATE_EMAIL)) { + throw new RuntimeException('Indica nome ed email di chi riceve il buono.'); + } + if (empty($row['target_idvariant'])) { + throw new RuntimeException('Questo buono non è configurato correttamente. Contatta la scuola.'); + } + $sel['recipient'] = [ + 'name' => mb_substr($name, 0, 191), + 'email' => mb_substr($email, 0, 191), + 'message' => mb_substr(trim((string) ($in['recipient_message'] ?? '')), 0, 500), + ]; + } + return $sel; + } + + /** idservice validi per un prodotto (classi singole + categorie intere) */ + public static function productServiceIds(int $idschool, int $idproduct): array + { + $st = self::pdo()->prepare( + "SELECT DISTINCT s.idservice + FROM product_services ps + JOIN service s ON s.idschool = ps.idschool + AND (s.idservice = ps.idservice OR (ps.idservicecategory IS NOT NULL AND s.category = ps.idservicecategory)) + WHERE ps.idproduct = ? AND ps.idschool = ?" + ); + $st->execute([$idproduct, $idschool]); + return array_map('intval', $st->fetchAll(PDO::FETCH_COLUMN)); + } + + public static function occupied(int $idschool, int $idschedule): int + { + $st = self::pdo()->prepare( + "SELECT COUNT(*) FROM bookingclass WHERE idserviceschedule = ? AND idschool = ? AND status IN ('booked', 'pending')" + ); + $st->execute([$idschedule, $idschool]); + return (int) $st->fetchColumn(); + } + + /** + * Posti liberi minimi sulle prossime $weeks lezioni di una classe. + * null = senza limite, -1 = nessuna lezione in calendario + */ + public static function fixedFree(int $idschool, int $idservice, int $weeks): ?int + { + $pdo = self::pdo(); + $st = $pdo->prepare("SELECT maxcapacity FROM service WHERE idservice = ? AND idschool = ?"); + $st->execute([$idservice, $idschool]); + $cap = (int) $st->fetchColumn(); + + $st = $pdo->prepare( + "SELECT (SELECT COUNT(*) FROM bookingclass b WHERE b.idserviceschedule = ss.idserviceschedule + AND b.idschool = ss.idschool AND b.status IN ('booked', 'pending')) AS taken + FROM serviceschedule ss + WHERE ss.idservice = ? AND ss.idschool = ? AND ss.dateschedule > NOW() + AND NOT EXISTS (SELECT 1 FROM dayoff d WHERE d.idschool = ss.idschool AND d.dayoffdate = DATE(ss.dateschedule)) + ORDER BY ss.dateschedule + LIMIT " . max(1, $weeks) + ); + $st->execute([$idservice, $idschool]); + $taken = array_map('intval', $st->fetchAll(PDO::FETCH_COLUMN)); + if (!$taken) { + return -1; + } + return $cap > 0 ? max(0, $cap - max($taken)) : null; + } + + /** + * Verifica un codice sconto per l'opzione scelta (l'utente è sempre quello della sessione). + * @return array idcoupon, code, discount + * @throws RuntimeException + */ + public static function checkCoupon(int $idschool, int $userId, string $code, array $variant): array + { + $code = strtoupper(trim($code)); + $price = (float) $variant['price']; + $pdo = self::pdo(); + + $st = $pdo->prepare("SELECT * FROM coupons WHERE idschool = ? AND code = ? AND active = 'Y' LIMIT 1"); + $st->execute([$idschool, $code]); + $c = $st->fetch(PDO::FETCH_ASSOC); + $today = date('Y-m-d'); + if (!$c || ($c['valid_from'] && $today < $c['valid_from']) || ($c['valid_to'] && $today > $c['valid_to'])) { + throw new RuntimeException('Codice non valido o scaduto.'); + } + + $st = $pdo->prepare("SELECT idproduct, idvariant FROM coupon_products WHERE idcoupon = ? AND idschool = ?"); + $st->execute([(int) $c['idcoupon'], $idschool]); + $limits = $st->fetchAll(PDO::FETCH_ASSOC); + if ($limits) { + $ok = false; + foreach ($limits as $l) { + if ( + (int) $l['idvariant'] === (int) $variant['idvariant'] + || ((int) $l['idproduct'] === (int) $variant['idproduct'] && empty($l['idvariant'])) + ) { + $ok = true; + } + } + if (!$ok) { + throw new RuntimeException('Questo codice non vale su questo prodotto.'); + } + } + if ($c['min_amount'] !== null && $price < (float) $c['min_amount']) { + throw new RuntimeException('Codice valido per acquisti da ' . number_format((float) $c['min_amount'], 2, ',', '.') . ' €.'); + } + if ($c['max_uses'] !== null) { + $st = $pdo->prepare("SELECT COUNT(*) FROM coupon_redemptions WHERE idcoupon = ? AND idschool = ?"); + $st->execute([(int) $c['idcoupon'], $idschool]); + if ((int) $st->fetchColumn() >= (int) $c['max_uses']) { + throw new RuntimeException('Codice esaurito.'); + } + } + if ($c['max_uses_per_user'] !== null) { + $st = $pdo->prepare("SELECT COUNT(*) FROM coupon_redemptions WHERE idcoupon = ? AND idschool = ? AND iduser = ?"); + $st->execute([(int) $c['idcoupon'], $idschool, $userId]); + if ((int) $st->fetchColumn() >= (int) $c['max_uses_per_user']) { + throw new RuntimeException('Hai già usato questo codice.'); + } + } + if ($c['new_students_only'] === 'Y') { + $st = $pdo->prepare("SELECT COUNT(*) FROM orderbook WHERE iduser = ? AND idschool = ?"); + $st->execute([$userId, $idschool]); + if ((int) $st->fetchColumn() > 0) { + throw new RuntimeException('Codice riservato alle nuove allieve.'); + } + } + $value = (float) $c['discount_value']; + $discount = $c['discount_type'] === 'fixed' ? min($value, $price) : round($price * min($value, 100) / 100, 2); + return ['idcoupon' => (int) $c['idcoupon'], 'code' => $c['code'], 'discount' => $discount]; + } + + /** Scadenza della tessera per un'opzione (Y-m-d o null) */ + public static function membershipEnd(int $idschool, array $variant, ?string $from = null): ?string + { + $from = $from ?? date('Y-m-d'); + if ($variant['validity_mode'] === 'calendar_year') { + return substr($from, 0, 4) . '-12-31'; + } + if ($variant['validity_mode'] === 'season') { + $start = max(1, min(12, (int) SchoolSettings::get('membership_season_start', 9, $idschool))); + $y = (int) substr($from, 0, 4); + $endYear = ((int) substr($from, 5, 2) >= $start) ? $y + 1 : $y; + return (new DateTimeImmutable(sprintf('%04d-%02d-01', $endYear, $start)))->modify('-1 day')->format('Y-m-d'); + } + if (!empty($variant['validity_value'])) { + return self::addPeriod($from, (int) $variant['validity_value'], (string) $variant['validity_unit'])->modify('-1 day')->format('Y-m-d'); + } + return null; + } + + public static function addPeriod(string $from, int $n, string $unit): DateTimeImmutable + { + $d = new DateTimeImmutable($from); + if ($unit === 'days') { + return $d->modify('+' . $n . ' days'); + } + if ($unit === 'weeks') { + return $d->modify('+' . ($n * 7) . ' days'); + } + // mesi senza sforare (31 gennaio + 1 mese = fine febbraio) + $y = (int) $d->format('Y'); + $m = (int) $d->format('n') + $n; + $y += intdiv($m - 1, 12); + $m = (($m - 1) % 12) + 1; + $last = (int) (new DateTimeImmutable(sprintf('%04d-%02d-01', $y, $m)))->format('t'); + return $d->setDate($y, $m, min((int) $d->format('j'), $last)); + } + + /** + * Crea l'ordine (orderbook) e tutto ciò che ne deriva, in un'unica transazione. + * - classe fissa: orderbook_services (le prenotazioni le crea la scuola alla propagazione) + * - lezione singola: prenotazione subito (bonifico = 'pending', carta = 'booked') + * - buono regalo: gift_vouchers in attesa del pagamento + * - tessera: la riga in memberships nasce alla conferma del pagamento + * @param string $method 'bank' | 'stripe' + * @return int idorderbook + */ + public static function createOrder(int $idschool, int $userId, array $sel, string $method, ?array $coupon): int + { + $pdo = self::pdo(); + $p = $sel['product']; + $v = $sel['variant']; + $mode = $sel['mode']; + $paid = $method === 'stripe'; + + $st = $pdo->prepare("SELECT first_name, last_name, email FROM auth_users WHERE id = ?"); + $st->execute([$userId]); + $u = $st->fetch(PDO::FETCH_ASSOC) ?: ['first_name' => '', 'last_name' => '', 'email' => '']; + + $price = round((float) $v['price'], 2); + $discount = $coupon ? min(round((float) $coupon['discount'], 2), $price) : 0.0; + $total = round($price - $discount, 2); + $lessons = $v['lessons'] !== null ? (int) $v['lessons'] : null; + $today = date('Y-m-d'); + + // Scadenza + $expire = null; + if ($mode === 'free' && $v['validity_mode'] === 'duration' && $v['validity_value'] && $v['validity_start'] === 'purchase') { + $expire = self::addPeriod($today, (int) $v['validity_value'], (string) $v['validity_unit'])->format('Y-m-d'); + } elseif ($mode === 'single' && $sel['schedule']) { + $expire = substr($sel['schedule']['dateschedule'], 0, 10); + } elseif ($mode === 'membership') { + $expire = self::membershipEnd($idschool, $v, $today); + } + + // Recuperi: dal prodotto, altrimenti dai parametri della scuola per quel numero di lezioni + $maxres = $p['max_reschedule'] !== null ? (int) $p['max_reschedule'] : null; + if ($maxres === null && $lessons && in_array($mode, ['fixed', 'free'], true)) { + $st = $pdo->prepare("SELECT reschedulenumber FROM expiryparameter WHERE quantityclass = ? AND idschool = ? LIMIT 1"); + $st->execute([$lessons, $idschool]); + $r = $st->fetchColumn(); + $maxres = $r !== false ? (int) $r : null; + } + if ($mode === 'single') { + $maxres = 0; + } + + $idservice = null; + if ($mode === 'fixed') { + $idservice = $sel['services'][0]; + } elseif ($mode === 'single') { + $idservice = (int) $sel['schedule']['idservice']; + } + + $snapshot = [ + 'mode' => $mode, + 'fixed_slots' => (int) $p['fixed_slots'], + 'weekly_limit' => $p['weekly_limit'] !== null ? (int) $p['weekly_limit'] : null, + 'max_reschedule' => $maxres, + 'lessons' => $lessons, + 'validity_mode' => $v['validity_mode'], + 'validity_value' => $v['validity_value'] !== null ? (int) $v['validity_value'] : null, + 'validity_unit' => $v['validity_unit'], + 'validity_start' => $v['validity_start'], + 'services' => $mode === 'free' || $mode === 'single' ? self::productServiceIds($idschool, (int) $p['idproduct']) : $sel['services'], + 'price' => $price, + ]; + + $pdo->beginTransaction(); + try { + // Lezione singola: blocca la riga della lezione e ricontrolla il posto + if ($mode === 'single') { + $st = $pdo->prepare("SELECT ss.idserviceschedule, s.maxcapacity FROM serviceschedule ss JOIN service s ON s.idservice = ss.idservice WHERE ss.idserviceschedule = ? AND ss.idschool = ? FOR UPDATE"); + $st->execute([(int) $sel['schedule']['idserviceschedule'], $idschool]); + $lock = $st->fetch(PDO::FETCH_ASSOC); + if (!$lock || ((int) $lock['maxcapacity'] > 0 && self::occupied($idschool, (int) $lock['idserviceschedule']) >= (int) $lock['maxcapacity'])) { + throw new RuntimeException('Nel frattempo la lezione si è riempita. Scegli un\'altra data.'); + } + } + + $pdo->prepare( + "INSERT INTO orderbook + (order_date_created, order_billing_email, order_total, product_name, line_total, quantity, + idservice, is_openflexy, iduser, nticket, expireon, status, quantityclass, + first_name, last_name, maxreschedule, reprogrammed, idschool, + idproduct, idvariant, booking_mode, weekly_limit, rules_snapshot, source, payment_status, + amount, discount_amount, idcoupon) + VALUES (?, ?, ?, ?, ?, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + )->execute([ + $today, + $u['email'], + number_format($total, 2, '.', ''), + mb_substr($p['title'] . ' · ' . $v['label'], 0, 200), + number_format($total, 2, '.', ''), + $idservice, + $mode === 'free' ? 'Y' : 'N', + $userId, + $lessons, + $expire, + $paid ? ($mode === 'fixed' ? 'pending' : 'completed') : 'on-hold', + $lessons, + $u['first_name'], + $u['last_name'], + $maxres, + $idschool, + (int) $p['idproduct'], + (int) $v['idvariant'], + in_array($mode, ['fixed', 'free', 'single'], true) ? $mode : null, + $p['weekly_limit'] !== null ? (int) $p['weekly_limit'] : null, + json_encode($snapshot, JSON_UNESCAPED_UNICODE), + $method, + $paid ? 'paid' : 'pending', + $total, + $discount > 0 ? $discount : null, + $coupon ? (int) $coupon['idcoupon'] : null, + ]); + $idorder = (int) $pdo->lastInsertId(); + + if ($mode === 'fixed') { + $ins = $pdo->prepare("INSERT INTO orderbook_services (idorderbook, idschool, idservice, slot) VALUES (?, ?, ?, ?)"); + foreach ($sel['services'] as $i => $sid) { + $ins->execute([$idorder, $idschool, $sid, $i + 1]); + } + } + + if ($mode === 'single') { + $pdo->prepare( + "INSERT INTO bookingclass (idserviceschedule, bookingstart, status, idservice, iduser, idorder, cancellation_token, idschool) + VALUES (?, ?, ?, ?, ?, ?, ?, ?)" + )->execute([ + (int) $sel['schedule']['idserviceschedule'], + $sel['schedule']['dateschedule'], + $paid ? 'booked' : 'pending', + (int) $sel['schedule']['idservice'], + $userId, + $idorder, + bin2hex(random_bytes(16)), + $idschool, + ]); + } + + if ($mode === 'voucher') { + $codeSt = $pdo->prepare("SELECT 1 FROM gift_vouchers WHERE idschool = ? AND code = ?"); + do { + $code = 'YB-' . self::randomCode(4) . '-' . self::randomCode(4); + $codeSt->execute([$idschool, $code]); + } while ($codeSt->fetchColumn()); + $vExpire = $v['validity_value'] ? self::addPeriod($today, (int) $v['validity_value'], (string) $v['validity_unit'])->format('Y-m-d') : null; + $pdo->prepare( + "INSERT INTO gift_vouchers (idschool, code, idvariant, buyer_iduser, buyer_name, buyer_email, recipient_name, recipient_email, + message, source, amount, expires_at, status) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" + )->execute([ + $idschool, + $code, + (int) $v['target_idvariant'], + $userId, + trim($u['first_name'] . ' ' . $u['last_name']), + $u['email'], + $sel['recipient']['name'], + $sel['recipient']['email'], + $sel['recipient']['message'] ?: null, + $method, + $total, + $vExpire, + $paid ? 'active' : 'pending', + ]); + // collega il buono all'ordine (per attivarlo alla conferma del pagamento) + $pdo->prepare("UPDATE orderbook SET cod = ? WHERE idorderbook = ?")->execute([$code, $idorder]); + } + + if ($mode === 'membership' && $paid) { + $pdo->prepare("INSERT INTO memberships (idschool, iduser, idorderbook, valid_from, valid_to, status) VALUES (?, ?, ?, ?, ?, 'active')") + ->execute([$idschool, $userId, $idorder, $today, $expire ?? '2099-12-31']); + } + + if ($coupon) { + $pdo->prepare("INSERT INTO coupon_redemptions (idcoupon, idschool, iduser, idorderbook, discount_amount) VALUES (?, ?, ?, ?, ?)") + ->execute([(int) $coupon['idcoupon'], $idschool, $userId, $idorder, $discount]); + } + + $pdo->commit(); + return $idorder; + } catch (Throwable $ex) { + if ($pdo->inTransaction()) { + $pdo->rollBack(); + } + throw $ex; + } + } + + /** Dati del bonifico per un ordine: intestatario, IBAN, banca, causale, scadenza */ + public static function bankInfo(int $idschool, array $order): array + { + $tpl = trim((string) SchoolSettings::get('bank_reference', '', $idschool)) ?: 'Ordine {ordine} - {nome}'; + $iban = strtoupper(preg_replace('/\s+/', '', (string) SchoolSettings::get('bank_iban', '', $idschool))); + $days = max(1, (int) SchoolSettings::get('bank_due_days', 5, $idschool)); + $created = $order['order_date_created'] ?: date('Y-m-d'); + return [ + 'holder' => (string) SchoolSettings::get('bank_holder', '', $idschool), + 'iban' => trim(chunk_split($iban, 4, ' ')), + 'bank' => (string) SchoolSettings::get('bank_name', '', $idschool), + 'reference' => mb_substr(strtr($tpl, ['{ordine}' => (string) $order['idorderbook'], '{nome}' => trim($order['first_name'] . ' ' . $order['last_name'])]), 0, 140), + 'due' => date('Y-m-d', strtotime($created . ' +' . $days . ' days')), + ]; + } + + /** + * La scuola conferma il pagamento (bonifico ricevuto) di un ordine in attesa. + * - ordine pagato + * - lezione singola: la prenotazione passa da 'pending' a 'booked' + * - tessera: nasce la riga in memberships + * - buono regalo: diventa attivo + * Idempotente: false se l'ordine non è (più) in attesa. + */ + public static function markPaid(int $idschool, int $idorder): bool + { + $pdo = self::pdo(); + $pdo->beginTransaction(); + try { + $st = $pdo->prepare( + "SELECT ob.*, p.kind FROM orderbook ob LEFT JOIN products p ON p.idproduct = ob.idproduct + WHERE ob.idorderbook = ? AND ob.idschool = ? FOR UPDATE" + ); + $st->execute([$idorder, $idschool]); + $o = $st->fetch(PDO::FETCH_ASSOC); + if (!$o || $o['payment_status'] !== 'pending') { + $pdo->rollBack(); + return false; + } + + // Classe fissa: 'pending' = da propagare (stesso significato degli ordini storici) + $pdo->prepare("UPDATE orderbook SET payment_status = 'paid', status = ? WHERE idorderbook = ? AND idschool = ?") + ->execute([$o['booking_mode'] === 'fixed' ? 'pending' : 'completed', $idorder, $idschool]); + + if ($o['booking_mode'] === 'single') { + $pdo->prepare("UPDATE bookingclass SET status = 'booked' WHERE idorder = ? AND idschool = ? AND status = 'pending'") + ->execute([$idorder, $idschool]); + } + if ($o['kind'] === 'membership') { + $pdo->prepare("INSERT INTO memberships (idschool, iduser, idorderbook, valid_from, valid_to, status) VALUES (?, ?, ?, CURDATE(), ?, 'active')") + ->execute([$idschool, (int) $o['iduser'], $idorder, $o['expireon'] ?: '2099-12-31']); + } + if (!empty($o['cod'])) { + $pdo->prepare("UPDATE gift_vouchers SET status = 'active' WHERE idschool = ? AND code = ? AND status = 'pending'") + ->execute([$idschool, $o['cod']]); + } + $pdo->commit(); + return true; + } catch (Throwable $ex) { + if ($pdo->inTransaction()) { + $pdo->rollBack(); + } + throw $ex; + } + } + + /** + * Annulla un ordine in attesa di pagamento (dall'allieva o dalla scuola): + * libera il posto della lezione singola, annulla il buono e l'uso del coupon. + * $userId: se indicato, solo se l'ordine è suo. + */ + public static function cancelPending(int $idschool, int $idorder, ?int $userId = null): bool + { + $pdo = self::pdo(); + $pdo->beginTransaction(); + try { + $sql = "SELECT * FROM orderbook WHERE idorderbook = ? AND idschool = ?" . ($userId ? " AND iduser = ?" : "") . " FOR UPDATE"; + $args = $userId ? [$idorder, $idschool, $userId] : [$idorder, $idschool]; + $st = $pdo->prepare($sql); + $st->execute($args); + $o = $st->fetch(PDO::FETCH_ASSOC); + if (!$o || $o['payment_status'] !== 'pending') { + $pdo->rollBack(); + return false; + } + $pdo->prepare("UPDATE orderbook SET payment_status = 'cancelled', status = 'cancelled' WHERE idorderbook = ? AND idschool = ?") + ->execute([$idorder, $idschool]); + $pdo->prepare("UPDATE bookingclass SET status = 'cancelled' WHERE idorder = ? AND idschool = ? AND status <> 'cancelled'") + ->execute([$idorder, $idschool]); + $pdo->prepare("DELETE FROM coupon_redemptions WHERE idorderbook = ? AND idschool = ?")->execute([$idorder, $idschool]); + if (!empty($o['cod'])) { + $pdo->prepare("UPDATE gift_vouchers SET status = 'cancelled' WHERE idschool = ? AND code = ? AND status = 'pending'") + ->execute([$idschool, $o['cod']]); + } + $pdo->commit(); + return true; + } catch (Throwable $ex) { + if ($pdo->inTransaction()) { + $pdo->rollBack(); + } + throw $ex; + } + } + + /** Ordini su cui la scuola deve agire: da pagare + da propagare (contatore in sidebar) */ + public static function pendingCount(int $idschool): int + { + $st = self::pdo()->prepare( + "SELECT COUNT(*) FROM orderbook + WHERE idschool = ? + AND (payment_status = 'pending' + OR (status = 'pending' AND (payment_status IS NULL OR payment_status = 'paid')))" + ); + $st->execute([$idschool]); + return (int) $st->fetchColumn(); + } + + private static function randomCode(int $len): string + { + $chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'; + $out = ''; + for ($i = 0; $i < $len; $i++) { + $out .= $chars[random_int(0, strlen($chars) - 1)]; + } + return $out; + } + + private static function pdo(): PDO + { + return DBHandlerSelect::getInstance()->getConnection(); + } +} diff --git a/public/include/sidebar.php b/public/include/sidebar.php index ed35cbd..20d43ff 100644 --- a/public/include/sidebar.php +++ b/public/include/sidebar.php @@ -57,19 +57,45 @@ if ($__mode === 'school' && $__isAdmin && !empty($__sc['idschool'])) { } } +// Percorso "Primi passi" non ancora concluso: promemoria con l'avanzamento salvato +$__setup = null; +if ($__mode === 'school' && $__isAdmin && !empty($__sc['idschool'])) { + try { + if ((string) SchoolSettings::get('setup_completed_at', '') === '') { + $__ss = json_decode((string) SchoolSettings::get('setup_state', ''), true); + $__setup = is_array($__ss) && !empty($__ss['progress']) ? (string) $__ss['progress'] : ''; + } + } catch (Throwable $__ex) { + error_log('[sidebar] primi passi: ' . $__ex->getMessage()); + } +} + +// Ordini su cui agire: da pagare + da propagare (contatore nel menu della scuola) +$__toPay = 0; +if ($__mode === 'school' && $__isAdmin && !empty($__sc['idschool'])) { + try { + require_once dirname(__DIR__) . '/class/ShopService.php'; + $__toPay = ShopService::pendingCount((int) $__sc['idschool']); + } catch (Throwable $__ex) { + error_log('[sidebar] ordini: ' . $__ex->getMessage()); + } +} + if (!function_exists('sb_item')) { /** Voce singola. $also = altre pagine che la accendono (es. il form di modifica). */ - function sb_item(string $href, string $icon, string $label, string $current, array $also = []): void + function sb_item(string $href, string $icon, string $label, string $current, array $also = [], int $badge = 0): void { $on = ($href === $current || in_array($current, $also, true)); echo '
  • ' . '' - . '' . htmlspecialchars($label, ENT_QUOTES, 'UTF-8') . '
  • '; + . '' . htmlspecialchars($label, ENT_QUOTES, 'UTF-8') . '' + . ($badge > 0 ? '' . $badge . '' : '') + . ''; } /** * Gruppo richiudibile (metisMenu). Si apre da solo se contiene la pagina corrente. - * $items = [ [href, etichetta, [pagine collegate]], ... ] (le voci null vengono saltate) + * $items = [ [href, etichetta, [pagine collegate], contatore], ... ] (le voci null vengono saltate) */ function sb_group(string $icon, string $label, array $items, string $current): void { @@ -78,7 +104,9 @@ if (!function_exists('sb_item')) { return; } $open = false; + $badge = 0; foreach ($items as $it) { + $badge += (int) ($it[3] ?? 0); if ($it[0] === $current || in_array($current, $it[2] ?? [], true)) { $open = true; } @@ -86,12 +114,16 @@ if (!function_exists('sb_item')) { echo '
  • ' . '' . '' - . '' . htmlspecialchars($label, ENT_QUOTES, 'UTF-8') . '' + . '' . htmlspecialchars($label, ENT_QUOTES, 'UTF-8') . '' + . ($badge > 0 ? '' . $badge . '' : '') + . '' . '
  • '; } @@ -210,6 +242,10 @@ if (!function_exists('sb_item')) { border-color: #cfe5e6; } + body[data-sidebar-size="sm"] .sb-badge { + display: none; + } + .sub-alert:hover { filter: brightness(.97); } @@ -270,6 +306,14 @@ if (!function_exists('sb_item')) {
    + + + + + Primi passiConfigura e prova la tua scuola + + + @@ -312,10 +356,7 @@ if (!function_exists('sb_item')) { ['statistiche.php', 'Statistiche'], ], $__page); ?> - + @@ -347,7 +390,8 @@ if (!function_exists('sb_item')) { - + + diff --git a/public/ordersummary.php b/public/ordersummary.php index e315bc5..fab6680 100644 --- a/public/ordersummary.php +++ b/public/ordersummary.php @@ -9,8 +9,6 @@ SchoolContext::requireSchoolAdmin(); $pdo = DBHandlerSelect::getInstance()->getConnection(); -if (!function_exists('e')) { - if (!function_exists('e')) { function e($value): string { diff --git a/public/package_rules.php b/public/package_rules.php new file mode 100644 index 0000000..861e592 --- /dev/null +++ b/public/package_rules.php @@ -0,0 +1,305 @@ +getConnection(); + +function e($value): string +{ + return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8'); +} + +function back(string $msg, string $type = 'msg'): void +{ + header('Location: package_rules.php?' . $type . '=' . urlencode($msg)); + exit(); +} + +/** Valori consigliati per una scuola che parte da zero */ +const PR_DEFAULTS = [[4, 5, 1], [6, 8, 2], [8, 10, 2], [10, 12, 2], [12, 15, 3]]; + +/* ---------------------------------------------------------------- AZIONI */ +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + yb_csrf_check(); + $action = (string) ($_POST['action'] ?? ''); + $id = (int) ($_POST['id'] ?? 0); + + $int = function (string $k, int $min, int $max): ?int { + $v = trim((string) ($_POST[$k] ?? '')); + return (ctype_digit($v) && (int) $v >= $min && (int) $v <= $max) ? (int) $v : null; + }; + + try { + if ($action === 'save') { + $qty = $int('quantityclass', 1, 200); + $exp = $int('expirylessons', 1, 400); + $res = $int('reschedulenumber', 0, 99); + if ($qty === null || $exp === null || $res === null) { + back('Controlla i valori: numeri interi, lezioni almeno 1.', 'err'); + } + if ($exp < $qty) { + back('La scadenza (' . $exp . ' lezioni) non può essere minore delle lezioni del pacchetto (' . $qty . ').', 'err'); + } + $st = $pdo->prepare("SELECT 1 FROM expiryparameter WHERE idschool = ? AND quantityclass = ? AND idexpiryparameter <> ? LIMIT 1"); + $st->execute([(int) $idschool, $qty, $id]); + if ($st->fetchColumn()) { + back('Esiste già una regola per i pacchetti da ' . $qty . ' lezioni.', 'err'); + } + if ($id > 0) { + $st = $pdo->prepare("UPDATE expiryparameter SET quantityclass = ?, expirylessons = ?, reschedulenumber = ? WHERE idexpiryparameter = ? AND idschool = ?"); + $st->execute([$qty, $exp, $res, $id, (int) $idschool]); + back('Regola per ' . $qty . ' lezioni aggiornata.'); + } + $pdo->prepare("INSERT INTO expiryparameter (quantityclass, expirylessons, reschedulenumber, idschool) VALUES (?, ?, ?, ?)") + ->execute([$qty, $exp, $res, (int) $idschool]); + back('Regola per ' . $qty . ' lezioni aggiunta.'); + } + + if ($action === 'delete' && $id > 0) { + $pdo->prepare("DELETE FROM expiryparameter WHERE idexpiryparameter = ? AND idschool = ?")->execute([$id, (int) $idschool]); + back('Regola eliminata.'); + } + + if ($action === 'defaults') { + $st = $pdo->prepare("SELECT COUNT(*) FROM expiryparameter WHERE idschool = ?"); + $st->execute([(int) $idschool]); + if ((int) $st->fetchColumn() > 0) { + back('Ci sono già delle regole: i valori consigliati si caricano solo su una tabella vuota.', 'err'); + } + $ins = $pdo->prepare("INSERT INTO expiryparameter (quantityclass, expirylessons, reschedulenumber, idschool) VALUES (?, ?, ?, ?)"); + foreach (PR_DEFAULTS as [$q, $x, $r]) { + $ins->execute([$q, $x, $r, (int) $idschool]); + } + back('Valori consigliati caricati: modificali come preferisci.'); + } + } catch (PDOException $ex) { + error_log('[package_rules] ' . $ex->getMessage()); + back('Errore database, operazione non eseguita.', 'err'); + } + back('Azione non valida.', 'err'); +} + +/* ------------------------------------------------------------------ DATI */ +$st = $pdo->prepare("SELECT * FROM expiryparameter WHERE idschool = ? ORDER BY quantityclass, idexpiryparameter"); +$st->execute([(int) $idschool]); +$rules = $st->fetchAll(PDO::FETCH_ASSOC); + +// Quanti ordini usano ogni numero di lezioni (per sapere cosa si tocca) +$st = $pdo->prepare("SELECT quantityclass, COUNT(*) AS n FROM orderbook WHERE idschool = ? AND quantityclass IS NOT NULL GROUP BY quantityclass"); +$st->execute([(int) $idschool]); +$usage = []; +foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $u) { + $usage[(int) $u['quantityclass']] = (int) $u['n']; +} +$missing = array_diff(array_keys($usage), array_map(fn($r) => (int) $r['quantityclass'], $rules)); +sort($missing); +?> + + + + + + YogiBook - Regole pacchetti + + + + + + + + + + + +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +
    +
    +
    +
    + +
    +
    + +
    +
    +
    Scadenza e recuperi dei pacchetti
    +

    + Per ogni pacchetto a numero di lezioni: dopo quante lezioni in calendario della sua classe scade, e quanti recuperi sono consentiti. + Valgono per la propagazione degli ordini, per gli ordini inseriti a mano e per i prodotti del negozio con "Recuperi" lasciato vuoto. +

    + +
    + +
    + Esempio: pacchetto da 8 lezioni, scade dopo 10 lezioni, 2 recuperi. + Se la classe è il martedì, il pacchetto vale per le prossime 10 lezioni del martedì (2 settimane di margine per le assenze) e l'allieva può spostare fino a 2 lezioni. + I giorni di chiusura non contano. +
    +
    + + +
    + +
    Ci sono ordini con un numero di lezioni senza regola: . Per questi la scadenza non si calcola da sola: aggiungi una regola o inseriscila a mano alla propagazione.
    +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Lezioni del pacchettoScade dopo (lezioni)Recuperi consentitiMargineOrdiniAzioni
    +
    + + Nessuna regola ancora. +
    + + + +
    +
    4 → 5 · 6 → 8 · 8 → 10 · 10 → 12 · 12 → 15, poi li modifichi.
    +
    +
    +
    + + + +
    + +
    + + scade prima di finire le lezioni + + + + + +
    + + + + +
    +
    +
    + + + +
    + +
    Nuova regola
    +
    +
    Le modifiche valgono per i prossimi calcoli: gli ordini già propagati mantengono scadenza e recuperi che hanno (li cambi da Ordini).
    +
    +
    + +
    +
    +
    + +
    +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/public/school_orders.php b/public/school_orders.php new file mode 100644 index 0000000..e110364 --- /dev/null +++ b/public/school_orders.php @@ -0,0 +1,1123 @@ +getConnection(); + +function e($value): string +{ + return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8'); +} + +function back(string $msg, string $type = 'msg'): void +{ + $f = preg_replace('/[^a-z]/', '', (string) ($_GET['f'] ?? '')); + header('Location: school_orders.php?' . http_build_query(array_filter(['f' => $f, $type => $msg]))); + exit(); +} + +/* ------------------------------------------------- AZIONI (pagamento, annullo) */ +if ($_SERVER['REQUEST_METHOD'] === 'POST') { + yb_csrf_check(); + $id = (int) ($_POST['id'] ?? 0); + if (!SchoolScope::belongs('orderbook', $id)) { + back('Ordine non trovato.', 'err'); + } + try { + $action = (string) ($_POST['action'] ?? ''); + if ($action === 'paid') { + ShopService::markPaid((int) $idschool, $id) + ? back('Pagamento registrato per l\'ordine n. ' . $id . '.') + : back('L\'ordine n. ' . $id . ' non è più in attesa di pagamento.', 'err'); + } + if ($action === 'cancel') { + ShopService::cancelPending((int) $idschool, $id) + ? back('Ordine n. ' . $id . ' annullato.') + : back('Si possono annullare solo gli ordini in attesa di pagamento.', 'err'); + } + } catch (PDOException $ex) { + error_log('[school_orders] ' . $ex->getMessage()); + back('Errore database, operazione non eseguita.', 'err'); + } + back('Azione non valida.', 'err'); +} + +/* ------------------------------------------------------------------ DATI */ +$st = $pdo->prepare( + "SELECT ob.idorderbook, ob.order_id, ob.order_date_created, ob.first_name, ob.last_name, ob.order_billing_email, + ob.product_name, ob.cod, ob.nticket, ob.quantityclass, ob.expireon, ob.status, ob.maxreschedule, ob.reprogrammed, + ob.is_openflexy, ob.booking_mode, ob.source, ob.payment_status, ob.amount, ob.discount_amount, ob.order_total, + p.kind, s.servicename, s.day, s.time, + (SELECT COUNT(*) FROM bookingclass b WHERE b.idorder = ob.idorderbook AND b.idschool = ob.idschool + AND b.status <> 'cancelled' AND b.is_gift = 'N') AS used, + (SELECT COUNT(*) FROM bookingclass b2 WHERE b2.idorder = ob.idorderbook AND b2.idschool = ob.idschool) AS anybooking + FROM orderbook ob + LEFT JOIN products p ON p.idproduct = ob.idproduct + LEFT JOIN service s ON s.idservice = ob.idservice AND s.idschool = ob.idschool + WHERE ob.idschool = ? + ORDER BY ob.idorderbook DESC + LIMIT 3000" +); +$st->execute([(int) $idschool]); +$raw = $st->fetchAll(PDO::FETCH_ASSOC); + +$ids = array_map(fn($o) => (int) $o['idorderbook'], $raw); +$classesBy = []; +$lessonBy = []; +$voucherBy = []; +if ($ids) { + $ph = implode(',', array_fill(0, count($ids), '?')); + $st = $pdo->prepare("SELECT os.idorderbook, s.servicename, s.day, s.time FROM orderbook_services os JOIN service s ON s.idservice = os.idservice WHERE os.idschool = ? AND os.idorderbook IN ($ph) ORDER BY os.slot"); + $st->execute(array_merge([(int) $idschool], $ids)); + foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $r) { + $classesBy[(int) $r['idorderbook']][] = trim($r['servicename'] . ' ' . $r['day'] . ' ' . $r['time']); + } + $st = $pdo->prepare("SELECT b.idorder, b.bookingstart, b.status FROM bookingclass b JOIN orderbook ob ON ob.idorderbook = b.idorder WHERE b.idschool = ? AND ob.booking_mode = 'single' AND b.idorder IN ($ph)"); + $st->execute(array_merge([(int) $idschool], $ids)); + foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $r) { + $lessonBy[(int) $r['idorder']] = $r; + } + $st = $pdo->prepare("SELECT ob.idorderbook, g.code, g.recipient_name FROM gift_vouchers g JOIN orderbook ob ON ob.cod = g.code COLLATE utf8mb4_general_ci AND ob.idschool = g.idschool WHERE g.idschool = ? AND ob.idorderbook IN ($ph)"); + $st->execute(array_merge([(int) $idschool], $ids)); + foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $r) { + $voucherBy[(int) $r['idorderbook']] = $r; + } +} + +$today = date('Y-m-d'); +$dueDays = max(1, (int) SchoolSettings::get('bank_due_days', 5)); +$sources = ['bank' => 'Bonifico', 'stripe' => 'Carta', 'manual' => 'Segreteria', 'voucher' => 'Buono regalo', 'woocommerce' => 'Sito']; + +$rows = []; +foreach ($raw as $o) { + $oid = (int) $o['idorderbook']; + $canc = in_array($o['payment_status'], ['cancelled', 'refunded'], true) || $o['status'] === 'cancelled'; + $pay = $o['payment_status'] === 'pending'; + if ($canc) { + $state = 'cancelled'; + } elseif ($pay) { + $state = 'topay'; + } elseif ($o['status'] === 'pending') { + $state = 'prop'; + } elseif ($o['expireon'] && $o['expireon'] < $today) { + $state = 'expired'; + } else { + $state = 'active'; + } + $details = $classesBy[$oid] ?? []; + if (!$details && $o['servicename'] && $o['booking_mode'] !== 'single') { + $details[] = trim($o['servicename'] . ' ' . $o['day'] . ' ' . $o['time']); + } + if (isset($lessonBy[$oid])) { + $details[] = ShopService::dateLabel(strtotime($lessonBy[$oid]['bookingstart'])) . ' (' . $lessonBy[$oid]['status'] . ')'; + } + if (isset($voucherBy[$oid])) { + $details[] = 'Buono per ' . $voucherBy[$oid]['recipient_name'] . ' · ' . $voucherBy[$oid]['code']; + } + $due = $pay ? date('Y-m-d', strtotime(($o['order_date_created'] ?: $today) . ' +' . $dueDays . ' days')) : null; + $amount = $o['amount'] !== null ? (float) $o['amount'] : (is_numeric(str_replace(',', '.', (string) $o['order_total'])) ? (float) str_replace(',', '.', (string) $o['order_total']) : null); + + $rows[] = [ + 'id' => $oid, + 'wc' => $o['order_id'], + 'date' => $o['order_date_created'], + 'name' => trim($o['first_name'] . ' ' . $o['last_name']), + 'email' => (string) $o['order_billing_email'], + 'product' => (string) ($o['product_name'] ?: ($o['servicename'] ?: $o['cod'])), + 'details' => $details, + 'used' => (int) $o['used'], + 'tot' => (int) $o['nticket'] > 0 ? (int) $o['nticket'] : (int) $o['quantityclass'], + 'expire' => $o['expireon'], + 'maxres' => $o['maxreschedule'] !== null ? (int) $o['maxreschedule'] : null, + 'reprog' => (int) $o['reprogrammed'], + 'amount' => $amount, + 'discount' => $o['discount_amount'] !== null ? (float) $o['discount_amount'] : null, + 'source' => $o['source'] ? ($sources[$o['source']] ?? $o['source']) : 'Storico', + 'state' => $state, + 'due' => $due, + 'flex' => $o['is_openflexy'] === 'Y', + 'single' => $o['booking_mode'] === 'single', + 'kind' => (string) $o['kind'], + 'bookings' => (int) $o['anybooking'], + ]; +} + +// Classi per il nuovo ordine +$st = $pdo->prepare("SELECT idservice, servicename, day, time FROM service WHERE idschool = ? ORDER BY servicename, day, time"); +$st->execute([(int) $idschool]); +$services = $st->fetchAll(PDO::FETCH_ASSOC); + +$f = preg_replace('/[^a-z]/', '', (string) ($_GET['f'] ?? '')); +$jsonFlags = JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP; +?> + + + + + + YogiBook - Ordini + + + + + + + + + + + +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +
    +
    + +
    +
    + +
    +
    +
    +
    +
    Ordini
    +

    Tutti gli ordini della scuola. Clicca su scadenza o recuperi per modificarli.

    +
    + +
    + +
    +
    + +
    + + + + + + + + + + + + + + + +
    N.AllievaProdottoLezioniScadenzaRecuperiImportoStatoAzioni
    +
    +
    +
    + + + + + + + +
    + +
    +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/public/school_setup.php b/public/school_setup.php new file mode 100644 index 0000000..00b27bb --- /dev/null +++ b/public/school_setup.php @@ -0,0 +1,510 @@ + date('Y-m-d H:i:s')], $sid); + header('Location: school_setup.php?done=1'); + exit(); + } + } + if ($action === 'reopen') { + SchoolSettings::save(['setup_completed_at' => null], $sid); + } + header('Location: school_setup.php' . ($key !== '' ? '#step-' . $key : '')); + exit(); +} + +/* ------------------------------------------------------------------ DATI */ +$steps = SchoolSetup::steps($sid, (int) $iduserlogin); +[$done, $total, $missing] = SchoolSetup::progress($steps); +$pct = $total ? (int) round($done / $total * 100) : 0; +$completedAt = (string) SchoolSettings::get('setup_completed_at', ''); + +// Avanzamento in cache per il promemoria in sidebar (scritto solo se cambia) +$state = SchoolSetup::state($sid); +if (($state['progress'] ?? '') !== $done . '/' . $total) { + $state['progress'] = $done . '/' . $total; + SchoolSetup::saveState($sid, $state); +} + +$next = null; +foreach ($steps as $s) { + if (!$s['done'] && !$s['skipped']) { + $next = $s; + break; + } +} +$byPhase = []; +foreach ($steps as $i => $s) { + $s['n'] = $i + 1; + $byPhase[$s['phase']][] = $s; +} +?> + + + + + + YogiBook - Primi passi + + + + + + + + + + +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    + +
    +
    + + + + + + + + + \ No newline at end of file diff --git a/public/shop.php b/public/shop.php new file mode 100644 index 0000000..a2c6bea --- /dev/null +++ b/public/shop.php @@ -0,0 +1,128 @@ +getConnection(); + +function e($value): string +{ + return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8'); +} + +$shopOn = SchoolSettings::get('shop_enabled', 'N') === 'Y'; +$shopUrl = (string) SchoolSettings::get('shop_url', ''); + +// Negozio spento: l'allieva vede il link esterno (se c'è); lo staff vede comunque il catalogo +$showCatalog = $shopOn || $isstaff; +$data = $showCatalog ? ShopService::catalog((int) $idschool, (int) $iduserlogin, true) : null; +if ($data) { + $data['schoolName'] = (string) $schoolname; +} +$jsonFlags = JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP; +?> + + + + + + Negozio - <?php echo e($schoolname); ?> + + + + + + + + + +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +
    +
    + + +
    +
    + +

    Il negozio non è ancora aperto

    + +

    Per acquistare pacchetti e abbonamenti usa il negozio online della scuola.

    + Vai al negozio + +

    Per acquistare chiedi in segreteria.

    + +
    +
    + + +
    +
    Il negozio non è ancora attivo per le allieve: lo vedi perché fai parte dello staff. Si attiva da Opzioni Scuola → Negozio.
    +
    + +
    + + + +
    + +
    +
    +
    + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/shop_checkout.php b/public/shop_checkout.php new file mode 100644 index 0000000..7fff27f --- /dev/null +++ b/public/shop_checkout.php @@ -0,0 +1,389 @@ +getConnection(); + +function e($value): string +{ + return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8'); +} + +function euro($v): string +{ + return number_format((float) $v, 2, ',', '.') . ' €'; +} + +if ($_SERVER['REQUEST_METHOD'] !== 'POST') { + header('Location: shop.php'); + exit(); +} +yb_csrf_check(); + +$shopOn = SchoolSettings::get('shop_enabled', 'N') === 'Y'; +if (!$shopOn && !$isstaff) { + header('Location: shop.php'); + exit(); +} +if (!SchoolScope::isMember((int) $iduserlogin)) { + header('Location: shop.php'); + exit(); +} + +$in = [ + 'idvariant' => (int) ($_POST['idvariant'] ?? 0), + 'services' => array_values(array_filter(array_map('intval', explode(',', (string) ($_POST['services'] ?? ''))))), + 'idschedule' => (int) ($_POST['idschedule'] ?? 0), + 'recipient_name' => (string) ($_POST['recipient_name'] ?? ''), + 'recipient_email' => (string) ($_POST['recipient_email'] ?? ''), + 'recipient_message' => (string) ($_POST['recipient_message'] ?? ''), +]; +$action = (string) ($_POST['action'] ?? 'review'); +$couponCode = strtoupper(trim((string) ($_POST['coupon_code'] ?? ''))); +$method = (string) ($_POST['method'] ?? ''); +$error = ''; +$couponMsg = ''; +$sel = null; +$coupon = null; + +try { + $sel = ShopService::selection((int) $idschool, (int) $iduserlogin, $in); +} catch (RuntimeException $ex) { + $error = $ex->getMessage(); +} catch (PDOException $ex) { + error_log('[shop_checkout] selection: ' . $ex->getMessage()); + $error = 'Si è verificato un errore. Riprova tra poco.'; +} + +if ($sel) { + if ($action === 'remove_coupon') { + $couponCode = ''; + } + if ($couponCode !== '') { + try { + $coupon = ShopService::checkCoupon((int) $idschool, (int) $iduserlogin, $couponCode, $sel['variant']); + } catch (RuntimeException $ex) { + $couponMsg = $ex->getMessage(); + $couponCode = ''; + } + } + + $methods = ShopService::paymentMethods((int) $idschool); + + if ($action === 'confirm') { + $token = (string) ($_POST['checkout_token'] ?? ''); + if ($token === '' || !hash_equals((string) ($_SESSION['yb_checkout_token'] ?? ''), $token)) { + $error = 'Questo ordine è già stato inviato. Controlla in "I miei pacchetti".'; + $sel = null; + } elseif (($_POST['terms'] ?? '') !== 'Y') { + $couponMsg = $couponMsg ?: ''; + $formError = 'Per continuare accetta le condizioni di acquisto.'; + } elseif (!(($method === 'bank' && $methods['bank']) || ($method === 'stripe' && $methods['card']))) { + $formError = 'Scegli come vuoi pagare.'; + } elseif ($method === 'stripe') { + $formError = 'Il pagamento con carta sarà disponibile a breve. Scegli il bonifico.'; + } else { + unset($_SESSION['yb_checkout_token']); + try { + $idorder = ShopService::createOrder((int) $idschool, (int) $iduserlogin, $sel, $method, $coupon); + header('Location: shop_order.php?id=' . $idorder . '&new=1'); + exit(); + } catch (RuntimeException $ex) { + $formError = $ex->getMessage(); + } catch (PDOException $ex) { + error_log('[shop_checkout] createOrder: ' . $ex->getMessage()); + $formError = 'Non è stato possibile registrare l\'ordine. Riprova.'; + } + } + } +} + +// Token monouso per la conferma +$_SESSION['yb_checkout_token'] = bin2hex(random_bytes(16)); + +/* ----------------------------------------------- dati per il riepilogo */ +$lines = []; +$termsUrl = (string) SchoolSettings::get('shop_terms_url', ''); +$termsText = (string) SchoolSettings::get('shop_terms_text', ''); +$membershipWarn = false; +if ($sel) { + $v = $sel['variant']; + $mode = $sel['mode']; + $price = (float) $v['price']; + $discount = $coupon ? min((float) $coupon['discount'], $price) : 0.0; + $total = round($price - $discount, 2); + $lessons = $v['lessons'] !== null ? (int) $v['lessons'] : null; + $unit = ['days' => ['giorno', 'giorni'], 'weeks' => ['settimana', 'settimane'], 'months' => ['mese', 'mesi']][$v['validity_unit']] ?? ['', '']; + $validity = $v['validity_value'] ? $v['validity_value'] . ' ' . ((int) $v['validity_value'] === 1 ? $unit[0] : $unit[1]) : ''; + + if ($mode === 'fixed') { + $st = $pdo->prepare("SELECT idservice, servicename, day, time FROM service WHERE idschool = ? AND idservice IN (" . implode(',', array_fill(0, count($sel['services']), '?')) . ")"); + $st->execute(array_merge([(int) $idschool], $sel['services'])); + $names = []; + foreach ($st->fetchAll(PDO::FETCH_ASSOC) as $s) { + $names[(int) $s['idservice']] = trim($s['servicename'] . ' · ' . $s['day'] . ' ' . $s['time']); + } + $lines[] = [count($sel['services']) > 1 ? 'Le tue classi' : 'La tua classe', implode(' + ', array_map(fn($sid) => $names[$sid] ?? '', $sel['services']))]; + $lines[] = ['Lezioni', $lessons ?: 'Illimitate']; + if ($validity) { + $lines[] = ['Validità', $validity . ($v['validity_start'] === 'purchase' ? ' dall\'acquisto' : ' dalla prima lezione')]; + } + $lines[] = ['Prima lezione', 'Te la conferma la scuola']; + } elseif ($mode === 'free') { + $lines[] = ['Lezioni', $lessons ?: 'Illimitate']; + if ($validity) { + $lines[] = ['Validità', $validity . ($v['validity_start'] === 'purchase' ? ' dall\'acquisto' : ' dalla prima lezione')]; + } + if ($sel['product']['weekly_limit']) { + $lines[] = ['Limite', 'Max ' . (int) $sel['product']['weekly_limit'] . ' lezioni a settimana']; + } + $lines[] = ['Prenotazioni', 'Le fai tu dal calendario']; + } elseif ($mode === 'single') { + $lines[] = ['Lezione', $sel['schedule']['servicename']]; + $lines[] = ['Quando', ShopService::dateLabel(strtotime($sel['schedule']['dateschedule']))]; + } elseif ($mode === 'membership') { + $end = ShopService::membershipEnd((int) $idschool, $v); + $lines[] = ['Validità', $end ? 'Fino al ' . date('d/m/Y', strtotime($end)) : 'Senza scadenza']; + } elseif ($mode === 'voucher') { + $lines[] = ['Per', $sel['recipient']['name']]; + $lines[] = ['Invio a', $sel['recipient']['email']]; + if ($validity) { + $lines[] = ['Scadenza del buono', $validity]; + } + } + + // Tessera obbligatoria mancante (avviso, non blocca) + if ($sel['product']['kind'] === 'lessons' && SchoolSettings::get('membership_required', 'N') === 'Y') { + $st = $pdo->prepare("SELECT 1 FROM memberships WHERE iduser = ? AND idschool = ? AND status = 'active' AND valid_to >= CURDATE() LIMIT 1"); + $st->execute([(int) $iduserlogin, (int) $idschool]); + $membershipWarn = !$st->fetchColumn(); + } + if ($method === '' || !(($method === 'bank' && $methods['bank']) || ($method === 'stripe' && $methods['card']))) { + $method = $methods['card'] ? 'stripe' : ($methods['bank'] ? 'bank' : ''); + } +} + +/** Campi nascosti che riportano la scelta a ogni invio */ +function keepFields(array $in, string $coupon): string +{ + $h = ''; + $h .= ''; + $h .= ''; + $h .= ''; + foreach (['recipient_name', 'recipient_email', 'recipient_message'] as $k) { + $h .= ''; + } + $h .= ''; + return $h; +} +?> + + + + + + Riepilogo ordine - <?php echo e($schoolname); ?> + + + + + + + + + +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +
    +
    +
    + + +
    + +

    Non possiamo completare l'ordine

    +

    + Torna al negozio +
    + + Modifica la scelta +

    Riepilogo

    + + +
    +
    +
    + + +
    +
    Per frequentare le lezioni serve anche la tessera associativa valida. Puoi acquistarla dal negozio dopo questo ordine.
    +
    + + +
    +
    + +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    + +
    +
    + + +
    +
    + + + + + +
    + · − + + +
    + +
    + + +
    +
    + +
    +
    +
    + + +
    + + + +
    + Come vuoi pagare? + +
    Il pagamento online non è ancora attivo. Contatta la segreteria per completare l'acquisto.
    + + + + + + + + +
    +
    Subtotale
    + 0) : ?>
    Sconto −
    +
    Totale
    +
    + + + + + + + +
    +
    +
    + + +
    +
    + +
    +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/public/shop_order.php b/public/shop_order.php new file mode 100644 index 0000000..2c51434 --- /dev/null +++ b/public/shop_order.php @@ -0,0 +1,285 @@ +getConnection(); + +function e($value): string +{ + return htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8'); +} + +function euro($v): string +{ + return number_format((float) $v, 2, ',', '.') . ' €'; +} + +$id = (int) ($_GET['id'] ?? $_POST['id'] ?? 0); +$st = $pdo->prepare("SELECT ob.*, p.title AS ptitle, p.kind FROM orderbook ob LEFT JOIN products p ON p.idproduct = ob.idproduct WHERE ob.idorderbook = ? AND ob.iduser = ? AND ob.idschool = ?"); +$st->execute([$id, (int) $iduserlogin, (int) $idschool]); +$o = $st->fetch(PDO::FETCH_ASSOC); +if (!$o) { + header('Location: shop.php'); + exit(); +} + +/* ------------------------------------------- annullo (solo bonifico in attesa) */ +if ($_SERVER['REQUEST_METHOD'] === 'POST' && ($_POST['action'] ?? '') === 'cancel') { + yb_csrf_check(); + try { + ShopService::cancelPending((int) $idschool, $id, (int) $iduserlogin); + } catch (PDOException $ex) { + error_log('[shop_order] cancel: ' . $ex->getMessage()); + header('Location: shop_order.php?id=' . $id . '&err=1'); + exit(); + } + header('Location: shop_order.php?id=' . $id . '&cancelled=1'); + exit(); +} + +/* ------------------------------------------------------------------ DATI */ +$rules = json_decode((string) $o['rules_snapshot'], true) ?: []; +$mode = $o['booking_mode'] ?: ($o['kind'] ?? ''); + +$classes = []; +if ($mode === 'fixed') { + $st = $pdo->prepare("SELECT s.servicename, s.day, s.time FROM orderbook_services os JOIN service s ON s.idservice = os.idservice WHERE os.idorderbook = ? AND os.idschool = ? ORDER BY os.slot"); + $st->execute([$id, (int) $idschool]); + $classes = $st->fetchAll(PDO::FETCH_ASSOC); +} +$lesson = null; +if ($mode === 'single') { + $st = $pdo->prepare("SELECT b.bookingstart, b.status, s.servicename FROM bookingclass b JOIN service s ON s.idservice = b.idservice WHERE b.idorder = ? AND b.idschool = ? ORDER BY b.idbookingclass LIMIT 1"); + $st->execute([$id, (int) $idschool]); + $lesson = $st->fetch(PDO::FETCH_ASSOC) ?: null; +} +$voucher = null; +if (!empty($o['cod'])) { + $st = $pdo->prepare("SELECT * FROM gift_vouchers WHERE idschool = ? AND code = ?"); + $st->execute([(int) $idschool, $o['cod']]); + $voucher = $st->fetch(PDO::FETCH_ASSOC) ?: null; +} + +$pending = $o['payment_status'] === 'pending'; +$cancelled = in_array($o['payment_status'], ['cancelled', 'refunded'], true); +$bank = ($o['source'] === 'bank' && $pending) ? ShopService::bankInfo((int) $idschool, $o) : null; +$isNew = isset($_GET['new']); + +$statusLabel = $cancelled ? ['Annullato', 'muted'] : ($pending ? ['In attesa di pagamento', 'warn'] : ['Pagato', 'ok']); + +$next = ''; +if (!$cancelled) { + if ($mode === 'fixed') { + $next = $pending + ? 'Quando la scuola riceve il bonifico ti conferma la data della prima lezione; da lì le lezioni vengono prenotate in automatico ogni settimana.' + : 'La scuola ti conferma la data della prima lezione; da lì le lezioni vengono prenotate in automatico ogni settimana.'; + } elseif ($mode === 'free') { + $next = $pending + ? 'Appena la scuola riceve il bonifico il pacchetto si attiva e puoi prenotare le lezioni dal calendario.' + : 'Il pacchetto è attivo: prenota le lezioni dal calendario quando vuoi.'; + } elseif ($mode === 'single' && $lesson) { + $next = 'Il tuo posto è ' . ($pending ? 'riservato in attesa del pagamento' : 'prenotato') . ': ' . $lesson['servicename'] . ', ' . mb_strtolower(ShopService::dateLabel(strtotime($lesson['bookingstart']))) . '.'; + } elseif ($o['kind'] === 'membership') { + $next = $pending ? 'La tessera si attiva quando la scuola riceve il pagamento.' : 'La tessera è attiva' . ($o['expireon'] ? ' fino al ' . date('d/m/Y', strtotime($o['expireon'])) : '') . '.'; + } elseif ($o['kind'] === 'voucher' && $voucher) { + $next = $pending + ? 'Il buono per ' . $voucher['recipient_name'] . ' si attiva quando la scuola riceve il pagamento.' + : 'Il buono per ' . $voucher['recipient_name'] . ' è attivo. Codice: ' . $voucher['code'] . '.'; + } +} +?> + + + + + + Ordine n. <?php echo (int) $id; ?> - <?php echo e($schoolname); ?> + + + + + + + + + + +
    +
    + +
    + +
    + +
    +
    + +
    +
    +
    + +
    +
    +
    +
    + + +
    +
    Ordine annullato.
    +
    + +
    +
    Non è stato possibile annullare l'ordine. Riprova o contatta la segreteria.
    +
    + + + +
    + +

    +

    +
    + + + +
    +
    Dati per il bonifico
    +
    +
    Intestatario
    +
    +
    IBAN
    +
    +
    Banca
    +
    +
    Importo
    +
    +
    Causale
    +
    +
    Entro il
    +
    +
    +
    Usa esattamente questa causale: così la scuola riconosce subito il tuo pagamento.
    +
    + + +
    +
    +
    +
    +
    Ordine n. del
    +
    + +
    +
    + +
    Classe
    +
    + + +
    Lezione
    +
    + +
    Lezioni
    +
    +
    Valido fino al
    +
    +
    Buono per
    +
    + 0) : ?>
    Sconto
    +
    −
    +
    Totale
    +
    ·
    +
    + +
    + +
    + +
    + + +
    + + + +
    + +
    + +
    +
    + +
    +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/public/uploads/schools/1/logo-40be84a1d014d11e.png b/public/uploads/schools/1/logo-40be84a1d014d11e.png new file mode 100644 index 0000000000000000000000000000000000000000..f48770404e90b616adc2febe8d8f939e18613f92 GIT binary patch literal 132161 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

    Q;Jsab(Pt;*zzS`1gPg6+%irg3-nD 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 literal 0 HcmV?d00001