var/cache/dev/twig/37/37a55cd2e97f05fc652094b8cf564887.php line 46

Open in your IDE?
  1. <?php
  2. use Twig\Environment;
  3. use Twig\Error\LoaderError;
  4. use Twig\Error\RuntimeError;
  5. use Twig\Extension\CoreExtension;
  6. use Twig\Extension\SandboxExtension;
  7. use Twig\Markup;
  8. use Twig\Sandbox\SecurityError;
  9. use Twig\Sandbox\SecurityNotAllowedTagError;
  10. use Twig\Sandbox\SecurityNotAllowedFilterError;
  11. use Twig\Sandbox\SecurityNotAllowedFunctionError;
  12. use Twig\Source;
  13. use Twig\Template;
  14. use Twig\TemplateWrapper;
  15. /* admin/sales/index.html.twig */
  16. class __TwigTemplate_3ff25a21a84d6e047978bc8154c2f3e1 extends Template
  17. {
  18.     private Source $source;
  19.     /**
  20.      * @var array<string, Template>
  21.      */
  22.     private array $macros = [];
  23.     public function __construct(Environment $env)
  24.     {
  25.         parent::__construct($env);
  26.         $this->source $this->getSourceContext();
  27.         $this->blocks = [
  28.             'title' => [$this'block_title'],
  29.             'head' => [$this'block_head'],
  30.             'body' => [$this'block_body'],
  31.             'javascript' => [$this'block_javascript'],
  32.         ];
  33.     }
  34.     protected function doGetParent(array $context): bool|string|Template|TemplateWrapper
  35.     {
  36.         // line 1
  37.         return "base.html.twig";
  38.     }
  39.     protected function doDisplay(array $context, array $blocks = []): iterable
  40.     {
  41.         $macros $this->macros;
  42.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  43.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "template""admin/sales/index.html.twig"));
  44.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  45.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "template""admin/sales/index.html.twig"));
  46.         $this->parent $this->load("base.html.twig"1);
  47.         yield from $this->parent->unwrap()->yield($contextarray_merge($this->blocks$blocks));
  48.         
  49.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  50.         
  51.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  52.     }
  53.     // line 3
  54.     /**
  55.      * @return iterable<null|scalar|\Stringable>
  56.      */
  57.     public function block_title(array $context, array $blocks = []): iterable
  58.     {
  59.         $macros $this->macros;
  60.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  61.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""title"));
  62.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  63.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""title"));
  64.         // line 4
  65.         yield "    ";
  66.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("sales", [], "messages");
  67.         
  68.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  69.         
  70.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  71.         yield from [];
  72.     }
  73.     // line 9
  74.     /**
  75.      * @return iterable<null|scalar|\Stringable>
  76.      */
  77.     public function block_head(array $context, array $blocks = []): iterable
  78.     {
  79.         $macros $this->macros;
  80.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  81.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""head"));
  82.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  83.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""head"));
  84.         // line 10
  85.         yield "    <style>
  86.         /* Keep all form elements at 12px on this page */
  87.         select, textarea, button { font-size: 12px !important; }
  88.         .form-control, .custom-select { font-size: 12px !important; }
  89.         /* Select2 text sizes */
  90.         .select2-container .select2-selection__rendered,
  91.         .select2-results__option,
  92.         .select2-container .select2-search__field { font-size: 12px !important; }
  93.         #adder-allocated-quantity,
  94.         #adder-quantity-unit {
  95.             vertical-align: middle;
  96.         }
  97.         .product-select-cell {
  98.             max-width: 250px;
  99.             /* Hücrenin alabileceği maksimum genişlik. İstediğiniz gibi ayarlayın. */
  100.             white-space: nowrap;
  101.             overflow: hidden;
  102.             text-overflow: ellipsis;
  103.         }
  104.         /* Ekleme Satırı Stilleri */
  105.         #adder-row {
  106.             background-color: #f8f9fa;
  107.             /* Hafif gri arkaplan */
  108.         }
  109.         #adder-row td {
  110.             vertical-align: middle;
  111.             padding: 0.25rem; /* Boşluk azaltıldı */
  112.             border-top: 2px dashed #e3e6f0;
  113.         }
  114.         /* Adder satırında hücreler arası yatay boşluğu minimuma indir */
  115.         #adder-row .input-group { margin-right: 4px; }
  116.         #adder-row .btn-icon, #adder-row .btn { margin-right: 4px; }
  117.         /* Yeni Card Header Stili */
  118.         .bg-light-blue {
  119.             background-color: #f0f3ff !important;
  120.             /* Hafif mavi arkaplan */
  121.         }
  122.         #product-list-table-tbody input {
  123.             /*border: none;*/
  124.             /*padding: 0;*/
  125.             /*margin: 0;*/
  126.             background-color: white;
  127.         }
  128.         .info-span {
  129.             color: red;
  130.             font-weight: bold;
  131.         }
  132.         .cost-detail-button {
  133.             color: blue;
  134.             font-width: bold;
  135.             border: none;
  136.             background-color: transparent;
  137.         }
  138.         .attention-icon {
  139.             display: inline-block;
  140.             vertical-align: middle;
  141.             margin-left: 5px;
  142.             font-size: 16px;
  143.             color: red;
  144.             font-weight: bold;
  145.         }
  146.         .quantity-input-added {
  147.             width: 60px;
  148.         }
  149.         .select2-container {
  150.             width: 100% !important;
  151.             /* Genişlik uyumluluğu için */
  152.         }
  153.         /* En kritik CSS düzeltmesi olmasa da, z-index çakışmalarına karşı bir güvencedir.
  154.            Asıl çözüm JavaScript'tedir. */
  155.         .select2-container--open {
  156.             z-index: 1056 !important;
  157.         }
  158.         .select2-container {
  159.             width: 100% !important;
  160.         }
  161.         .select2-container--open {
  162.             z-index: 1056 !important;
  163.         }
  164.         .select2-container--bootstrap4 .select2-selection--single
  165.         {
  166.             padding: .50rem !important;
  167.         }
  168.         .select2-container .select2-selection--single {
  169.             height: 28px !important;
  170.         }
  171.         /* === SEÇİM KARTLARI İÇİN CSS === */
  172.         .selection-card-label {
  173.             display: block;
  174.             cursor: pointer;
  175.             width: 100%;
  176.         }
  177.         .selection-card {
  178.             border: 2px solid #e3e6f0;
  179.             border-radius: 0.5rem;
  180.             padding: 0.50rem;
  181.             transition: all 0.2s ease-in-out;
  182.             display: flex;
  183.             justify-content: center;
  184.             align-items: center;
  185.             width: 100%;
  186.         }
  187.         /* Kartın üzerine gelindiğinde (hover) */
  188.         .selection-card:hover {
  189.             border-color: #4e73df;
  190.             transform: translateY(-2px);
  191.             /* Hafif yukarı kalkma efekti */
  192.             box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);
  193.         }
  194.         /* Kart içindeki başlık (Fatura, Proforma) */
  195.         .selection-title {
  196.             font-size: 1.1rem;
  197.             font-weight: 500;
  198.             color: #5a5c69;
  199.             transition: color 0.2s ease-in-out;
  200.         }
  201.         /* Onay işareti (başlangıçta gizli) */
  202.         .checkmark {
  203.             font-size: 1.25rem;
  204.             color: #4e73df;
  205.             opacity: 0;
  206.             transform: scale(0.5);
  207.             transition: all 0.2s ease-out;
  208.             margin-left: 0.75rem;
  209.         }
  210.         /* SEÇİM YAPILDIĞINDAKİ STİLLER */
  211.         /* CSS :has() seçicisi ile, içindeki radio input seçili olan etiketin kartını stillendiriyoruz. */
  212.         .selection-card-label:has(input[type=\"radio\"]:checked) .selection-card {
  213.             border-color: #4e73df;
  214.             background-color: #f0f3ff;
  215.         }
  216.         /* Seçili kartın başlık rengini değiştir */
  217.         .selection-card-label:has(input[type=\"radio\"]:checked) .selection-title {
  218.             color: #4e73df;
  219.             font-weight: 600;
  220.         }
  221.         /* Seçili kartın onay işaretini görünür yap */
  222.         .selection-card-label:has(input[type=\"radio\"]:checked) .checkmark {
  223.             opacity: 1;
  224.             transform: scale(1);
  225.         }
  226.         /* Bilgi satırı için stil */
  227.         #info-details-content {
  228.             background-color: #f1faff;
  229.             /* Hafif mavi arka plan */
  230.             border-bottom: 2px dashed #e3e6f0;
  231.             /* Altına kesikli çizgi ekler */
  232.         }
  233.         .info-details-content-class {
  234.             background-color: #f1faff;
  235.             /* Hafif mavi arka plan */
  236.             border-bottom: 2px dashed #e3e6f0;
  237.             /* Altına kesikli çizgi ekler */
  238.         }
  239.         /* Make product table full-width and remove right gaps */
  240.         .card-body > .table-responsive { padding-right: 0; }
  241.         #product-list-table { width: 100% !important; table-layout: fixed; }
  242.         #product-list-table th, #product-list-table td { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  243.         #product-list-table .product-select-cell select { width: 100%; }
  244.         /* Adjust specific column widths to fit viewport */
  245.         .summary-row td {
  246.             border-top: none;
  247.             background-color: #f8f9fc;
  248.             padding: 0;
  249.         }
  250.         .sale-summary-row {
  251.             display: flex;
  252.             justify-content: flex-end;
  253.             align-items: center;
  254.             gap: 12px;
  255.             padding: 0.35rem 0.75rem;
  256.             border-radius: 0.35rem;
  257.             margin-right: 1.5rem;
  258.         }
  259.         .sale-summary-row .summary-label {
  260.             font-weight: 600;
  261.             color: #4b5563;
  262.             white-space: nowrap;
  263.         }
  264.         .sale-summary-row .summary-value {
  265.             font-weight: 700;
  266.             color: #111827;
  267.             text-align: right;
  268.             min-width: 120px;
  269.             white-space: nowrap;
  270.         }
  271.         .sale-summary-row.summary-tax .summary-label,
  272.         .sale-summary-row.summary-tax .summary-value {
  273.             display: flex;
  274.             flex-direction: column;
  275.             align-items: flex-end;
  276.             gap: 4px;
  277.         }
  278.         .sale-summary-row.summary-tax .summary-label div,
  279.         .sale-summary-row.summary-tax .summary-value div {
  280.             white-space: nowrap;
  281.         }
  282.         .sale-summary-row.summary-total .summary-value {
  283.             font-size: 1.25rem;
  284.         }
  285.         #product-list-table th:nth-child(1), #product-list-table td:nth-child(1) { width: 5%; }
  286.         #product-list-table th:nth-child(2), #product-list-table td:nth-child(2) { width: 25%; }
  287.         #product-list-table th:nth-child(3), #product-list-table td:nth-child(3) { width: 10%; }
  288.         #product-list-table th:nth-child(4), #product-list-table td:nth-child(4) { width: 10%; }
  289.         #product-list-table th:nth-child(5), #product-list-table td:nth-child(5) { width: 10%; }
  290.         #product-list-table th:nth-child(6), #product-list-table td:nth-child(6) { width: 8%; }
  291.         #product-list-table th:nth-child(7), #product-list-table td:nth-child(7) { width: 8%; }
  292.         #product-list-table th:nth-child(8), #product-list-table td:nth-child(8) { width: 15%; }
  293.         #product-list-table th:nth-child(9), #product-list-table td:nth-child(9) { width: 9%; }
  294.     </style>
  295. ";
  296.         
  297.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  298.         
  299.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  300.         yield from [];
  301.     }
  302.     // line 256
  303.     /**
  304.      * @return iterable<null|scalar|\Stringable>
  305.      */
  306.     public function block_body(array $context, array $blocks = []): iterable
  307.     {
  308.         $macros $this->macros;
  309.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  310.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""body"));
  311.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  312.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""body"));
  313.         // line 257
  314.         yield "    <div class=\"container-fluid m-0 p-0\">
  315.         <div class=\"card shadow mb-4\">
  316.             <div class=\"card-header py-3 d-flex justify-content-between align-items-center\">
  317.                 <div class=\"btn-group\" role=\"group\">
  318.                     <div class=\"d-md-none\">
  319.                         <div class=\"dropdown\">
  320.                             <button class=\"btn btn-secondary dropdown-toggle\" type=\"button\" id=\"dropdownMenuButton\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\">
  321.                                 ";
  322.         // line 265
  323.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("actions", [], "messages");
  324.         // line 266
  325.         yield "                            </button>
  326.                             <div class=\"dropdown-menu\" aria-labelledby=\"dropdownMenuButton\">
  327.                                 <button type=\"button\" class=\"dropdown-item\" data-toggle=\"modal\" data-target=\"#payments-modal\">
  328.                                     <i class=\"fas fa-money-check-alt mr-1\"></i>
  329.                                     ";
  330.         // line 270
  331.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("payments", [], "messages");
  332.         // line 271
  333.         yield "                                </button>
  334.                                 <button type=\"button\" data-toggle=\"modal\" data-target=\"#add-customer-modal\" class=\"dropdown-item\">
  335.                                     <i class=\"fas fa-user-plus mr-1\"></i>
  336.                                     ";
  337.         // line 274
  338.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("addCustomer", [], "messages");
  339.         // line 275
  340.         yield "                                </button>
  341.                                 <button type=\"button\" class=\"dropdown-item js-edit-customer\">
  342.                                     <i class=\"fas fa-user-edit mr-1\"></i>
  343.                                     ";
  344.         // line 278
  345.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("editCustomer", [], "messages");
  346.         // line 279
  347.         yield "                                </button>
  348.                                 <button type=\"button\" class=\"dropdown-item\" id=\"btn-gift-voucher-mobile\">
  349.                                     <i class=\"fas fa-gift mr-1\"></i>
  350.                                     ";
  351.         // line 282
  352.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("giftVoucher"), "html"nulltrue);
  353.         yield "
  354.                                 </button>
  355.                             </div>
  356.                         </div>
  357.                     </div>
  358.                     <div class=\"d-none d-md-block\">
  359.                         <div class=\"btn-group\" role=\"group\">
  360.                             <button type=\"button\" class=\"btn btn-outline-secondary\" data-toggle=\"modal\" data-target=\"#payments-modal\">
  361.                                 <i class=\"fas fa-money-check-alt mr-1\"></i>
  362.                                 ";
  363.         // line 292
  364.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("payments", [], "messages");
  365.         // line 293
  366.         yield "                            </button>
  367.                             <button type=\"button\" data-toggle=\"modal\" data-target=\"#add-customer-modal\" class=\"btn btn-outline-secondary\">
  368.                                 <i class=\"fas fa-user-plus mr-1\"></i>
  369.                                 ";
  370.         // line 296
  371.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("addCustomer", [], "messages");
  372.         // line 297
  373.         yield "                            </button>
  374.                             <button type=\"button\" class=\"btn btn-outline-secondary js-edit-customer\">
  375.                                 ";
  376.         // line 299
  377.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("editCustomer", [], "messages");
  378.         // line 300
  379.         yield "                            </button>
  380.                             <button type=\"button\" class=\"btn btn-outline-secondary\" id=\"btn-gift-voucher\" title=\"";
  381.         // line 301
  382.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("useGiftVoucher"), "html"nulltrue);
  383.         yield "\">
  384.                                 <i class=\"fas fa-gift mr-1\"></i>
  385.                                 ";
  386.         // line 303
  387.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("giftVoucher"), "html"nulltrue);
  388.         yield "
  389.                             </button>
  390.                         </div>
  391.                     </div>
  392.                 </div>
  393.                 <button type=\"button\" id=\"submitbtn\" class=\"btn btn-success\">
  394.                     <i class=\"fas fa-save mr-1\"></i>
  395.                     ";
  396.         // line 312
  397.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("save", [], "messages");
  398.         // line 315
  399.         yield "                </button>
  400.             </div>
  401.             <div class=\"card-body\">
  402.                 ";
  403.         // line 319
  404.         yield "                <div class=\"form-group\">
  405.                     <label class=\"form-label font-weight-bold\">";
  406.         // line 320
  407.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("salesType"), "html"nulltrue);
  408.         yield "</label>
  409.                     <div class=\"row\">
  410.                         ";
  411.         // line 323
  412.         yield "                        <div class=\"col-md-6\">
  413.                             <label class=\"selection-card-label\">
  414.                                 <input type=\"radio\" name=\"salesType\" class=\"d-none\" value=\"invoice\">
  415.                                 <div class=\"selection-card\">
  416.                                     <span class=\"selection-title\">";
  417.         // line 327
  418.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("invoice", [], "messages");
  419.         yield "</span>
  420.                                     <i class=\"fas fa-check-circle checkmark\"></i>
  421.                                 </div>
  422.                             </label>
  423.                         </div>
  424.                         ";
  425.         // line 334
  426.         yield "                        <div class=\"col-md-6\">
  427.                             <label class=\"selection-card-label\">
  428.                                 <input type=\"radio\" name=\"salesType\" class=\"d-none\" value=\"proforma\" checked>
  429.                                 <div class=\"selection-card\">
  430.                                     <span class=\"selection-title\">";
  431.         // line 338
  432.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("proforma", [], "messages");
  433.         yield "</span>
  434.                                     <i class=\"fas fa-check-circle checkmark\"></i>
  435.                                 </div>
  436.                             </label>
  437.                         </div>
  438.                     </div>
  439.                 </div>
  440.                 <div style=\"margin-bottom: 10px\">
  441.                     ";
  442.         // line 347
  443.         yield "                    ";
  444.         yield         $this->env->getRuntime('Symfony\Component\Form\FormRenderer')->renderBlock((isset($context["form"]) || array_key_exists("form"$context) ? $context["form"] : (function () { throw new RuntimeError('Variable "form" does not exist.'347$this->source); })()), 'form_start');
  445.         yield "
  446.                     <div class=\"\">
  447.                         <div class=\"row\">
  448.                             <div class=\"col-lg-6 col-md-12\">
  449.                                 ";
  450.         // line 351
  451.         yield $this->env->getRuntime('Symfony\Component\Form\FormRenderer')->searchAndRenderBlock(CoreExtension::getAttribute($this->env$this->source, (isset($context["form"]) || array_key_exists("form"$context) ? $context["form"] : (function () { throw new RuntimeError('Variable "form" does not exist.'351$this->source); })()), "totalPurchasePrice", [], "any"falsefalsefalse351), 'row');
  452.         yield "
  453.                                 ";
  454.         // line 352
  455.         yield $this->env->getRuntime('Symfony\Component\Form\FormRenderer')->searchAndRenderBlock(CoreExtension::getAttribute($this->env$this->source, (isset($context["form"]) || array_key_exists("form"$context) ? $context["form"] : (function () { throw new RuntimeError('Variable "form" does not exist.'352$this->source); })()), "status", [], "any"falsefalsefalse352), 'row');
  456.         yield "
  457.                             </div>
  458.                             <div class=\"col-lg-6 col-md-12\">
  459.                                 ";
  460.         // line 355
  461.         yield $this->env->getRuntime('Symfony\Component\Form\FormRenderer')->searchAndRenderBlock(CoreExtension::getAttribute($this->env$this->source, (isset($context["form"]) || array_key_exists("form"$context) ? $context["form"] : (function () { throw new RuntimeError('Variable "form" does not exist.'355$this->source); })()), "customer", [], "any"falsefalsefalse355), 'row');
  462.         yield "
  463.                                 ";
  464.         // line 356
  465.         yield $this->env->getRuntime('Symfony\Component\Form\FormRenderer')->searchAndRenderBlock(CoreExtension::getAttribute($this->env$this->source, (isset($context["form"]) || array_key_exists("form"$context) ? $context["form"] : (function () { throw new RuntimeError('Variable "form" does not exist.'356$this->source); })()), "seller", [], "any"falsefalsefalse356), 'row');
  466.         yield "
  467.                             </div>
  468.                         </div>
  469.                         <div class=\"row\">
  470.                             <div class=\"col-lg-3 col-md-6\">";
  471.         // line 360
  472.         yield $this->env->getRuntime('Symfony\Component\Form\FormRenderer')->searchAndRenderBlock(CoreExtension::getAttribute($this->env$this->source, (isset($context["form"]) || array_key_exists("form"$context) ? $context["form"] : (function () { throw new RuntimeError('Variable "form" does not exist.'360$this->source); })()), "salesDate", [], "any"falsefalsefalse360), 'row');
  473.         yield "</div>
  474.                             <div class=\"col-lg-3 col-md-6\">";
  475.         // line 361
  476.         yield $this->env->getRuntime('Symfony\Component\Form\FormRenderer')->searchAndRenderBlock(CoreExtension::getAttribute($this->env$this->source, (isset($context["form"]) || array_key_exists("form"$context) ? $context["form"] : (function () { throw new RuntimeError('Variable "form" does not exist.'361$this->source); })()), "deliveryDate", [], "any"falsefalsefalse361), 'row');
  477.         yield "</div>
  478.                             <div class=\"col-lg-3 col-md-6\">";
  479.         // line 362
  480.         yield $this->env->getRuntime('Symfony\Component\Form\FormRenderer')->searchAndRenderBlock(CoreExtension::getAttribute($this->env$this->source, (isset($context["form"]) || array_key_exists("form"$context) ? $context["form"] : (function () { throw new RuntimeError('Variable "form" does not exist.'362$this->source); })()), "dueDate", [], "any"falsefalsefalse362), 'row');
  481.         yield "</div>
  482.                             <div class=\"col-lg-3 col-md-6\">";
  483.         // line 363
  484.         yield $this->env->getRuntime('Symfony\Component\Form\FormRenderer')->searchAndRenderBlock(CoreExtension::getAttribute($this->env$this->source, (isset($context["form"]) || array_key_exists("form"$context) ? $context["form"] : (function () { throw new RuntimeError('Variable "form" does not exist.'363$this->source); })()), "validDate", [], "any"falsefalsefalse363), 'row');
  485.         yield "</div>
  486.                         </div>
  487.                     </div>
  488.                     ";
  489.         // line 367
  490.         yield "
  491.                     ";
  492.         // line 369
  493.         yield "                    <div class=\"modal fade\" id=\"payments-modal\" role=\"dialog\" aria-labelledby=\"paymentsModalLabel\" aria-hidden=\"true\">
  494.                         <div class=\"modal-dialog modal-xl\" role=\"document\">
  495.                             <div class=\"modal-content\">
  496.                                 <div class=\"modal-header\">
  497.                                     <h5 class=\"modal-title\" id=\"paymentsModalLabel\">";
  498.         // line 373
  499.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("payments", [], "messages");
  500.         yield "</h5>
  501.                                     <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\">
  502.                                         <span aria-hidden=\"true\">&times;</span>
  503.                                     </button>
  504.                                 </div>
  505.                                 <div class=\"modal-body\">
  506.                                     <div class=\"card mb-1\">
  507.                                         <div class=\"card-header d-flex align-items-center justify-content-between\">
  508.                                             <div>
  509.                                                 <h5 class=\"mb-0\">";
  510.         // line 382
  511.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("payments", [], "messages");
  512.         yield "</h5>
  513.                                                 <div style=\"float: left; width: 250px\">
  514.                                                     ";
  515.         // line 384
  516.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("total", [], "messages");
  517.         yield ":
  518.                                                     <span id=\"total-amount-span\"></span>
  519.                                                     ";
  520.         // line 386
  521.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("remainingAmount", [], "messages");
  522.         yield ":
  523.                                                     <span id=\"remainder-amount-span\"></span>
  524.                                                 </div>
  525.                                             </div>
  526.                                             <button class=\"btn btn-primary\" type=\"button\" id=\"btn-addPayment\" data-toggle=\"modal\" data-target=\"#add-payment-modal\">
  527.                                                 ";
  528.         // line 391
  529.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("addPayment", [], "messages");
  530.         // line 392
  531.         yield "                                            </button>
  532.                                         </div>
  533.                                         <div class=\"card-body\">
  534.                                             <div>
  535.                                                 <table class=\"table\" id=\"payment-list-table\">
  536.                                                     <thead>
  537.                                                     <tr>
  538.                                                         <th>";
  539.         // line 399
  540.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("amount", [], "messages");
  541.         yield "</th>
  542.                                                         <th>";
  543.         // line 400
  544.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("status", [], "messages");
  545.         yield "</th>
  546.                                                         <th>";
  547.         // line 401
  548.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("paymentDate", [], "messages");
  549.         yield "</th>
  550.                                                         <th>";
  551.         // line 402
  552.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("dueDate", [], "messages");
  553.         yield "</th>
  554.                                                         <th>";
  555.         // line 403
  556.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("paymentMethod", [], "messages");
  557.         yield "</th>
  558.                                                         <th>";
  559.         // line 404
  560.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("description", [], "messages");
  561.         yield "</th>
  562.                                                         <th>&nbsp;</th>
  563.                                                     </tr>
  564.                                                     </thead>
  565.                                                     <tbody id=\"payment-list-table-tbody\"></tbody>
  566.                                                 </table>
  567.                                             </div>
  568.                                         </div>
  569.                                     </div>
  570.                                 </div>
  571.                             </div>
  572.                         </div>
  573.                     </div>
  574.                     <div class=\"card border-0 shadow-sm\">
  575.                         <div class=\"card-header bg-light-blue border-0 py-3\">
  576.                             <div class=\"row align-items-center\">
  577.                                 <div class=\"col-md-4\">
  578.                                     <label for=\"warehouse-select\" class=\"font-weight-bold mb-1\">";
  579.         // line 422
  580.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("warehouse", [], "messages");
  581.         yield "</label>
  582.                                     <select id=\"warehouseselect\" class=\"form-control\">
  583.                                         <option value=\"\">";
  584.         // line 424
  585.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("selectwarehouse", [], "messages");
  586.         yield "</option>
  587.                                         ";
  588.         // line 425
  589.         $context['_parent'] = $context;
  590.         $context['_seq'] = CoreExtension::ensureTraversable((isset($context["warehouses"]) || array_key_exists("warehouses"$context) ? $context["warehouses"] : (function () { throw new RuntimeError('Variable "warehouses" does not exist.'425$this->source); })()));
  591.         foreach ($context['_seq'] as $context["_key"] => $context["warehouse"]) {
  592.             // line 426
  593.             yield "                                            <option value=\"";
  594.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["warehouse"], "id", [], "any"falsefalsefalse426), "html"nulltrue);
  595.             yield "\">";
  596.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["warehouse"], "name", [], "any"falsefalsefalse426), "html"nulltrue);
  597.             yield "</option>
  598.                                         ";
  599.         }
  600.         $_parent $context['_parent'];
  601.         unset($context['_seq'], $context['_key'], $context['warehouse'], $context['_parent']);
  602.         $context array_intersect_key($context$_parent) + $_parent;
  603.         // line 428
  604.         yield "                                    </select>
  605.                                 </div>
  606.                                 <div class=\"col-md-5\"></div>
  607.                                 <div id=\"product-info-box\" class=\"col-md-3\" style=\"display: none;\">
  608.                                     <div class=\"info-box-content\">
  609.                                         <div>
  610.                                             ";
  611.         // line 434
  612.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("stockQuantity", [], "messages");
  613.         yield ":
  614.                                             <strong id=\"info-stock\"></strong>
  615.                                         </div>
  616.                                         <div>
  617.                                             ";
  618.         // line 438
  619.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("averageCost", [], "messages");
  620.         yield ":
  621.                                             <strong id=\"info-cost\"></strong>
  622.                                         </div>
  623.                                     </div>
  624.                                 </div>
  625.                             </div>
  626.                         </div>
  627.                         <div class=\"card-body\" style=\"padding: 0\">
  628.                             <div class=\"table-responsive\">
  629.                                 <table class=\"table modern-table\" id=\"product-list-table\" style=\"width: 100%;\">
  630.                                     <thead>
  631.                                     <tr>
  632.                                         <th style=\"width: 5%;\">";
  633.         // line 451
  634.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("info", [], "messages");
  635.         yield "</th>
  636.                                         <th style=\"width: 20%;\">";
  637.         // line 452
  638.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("product", [], "messages");
  639.         yield "</th>
  640.                                         <th style=\"width: 20%;\">";
  641.         // line 453
  642.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("quantity", [], "messages");
  643.         yield "</th>
  644.                                         <th style=\"width: 15%;\">";
  645.         // line 454
  646.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("unitPrice", [], "messages");
  647.         yield "</th>
  648.                                         <th style=\"width: 10%;\">";
  649.         // line 455
  650.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("discount", [], "messages");
  651.         yield " (%)</th>
  652.                                         <th style=\"width: 10%;\">TVA (%)</th>
  653.                                         <th style=\"width: 15%; text-align: left !important;\" class=\"text-right\">";
  654.         // line 457
  655.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("total", [], "messages");
  656.         yield "</th>
  657.                                         <th style=\"width: 15%;\" class=\"text-center\">";
  658.         // line 458
  659.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("action", [], "messages");
  660.         yield "</th>
  661.                                     </tr>
  662.                                     </thead>
  663.                                     <tbody id=\"product-list-table-tbody\">
  664.                                     </tbody>
  665.                                     <tbody id=\"adder-body\">
  666.                                     <tr id=\"adder-row\">
  667.                                         <td>
  668.                                             <button type=\"button\" id=\"show-info-btn\"
  669.                                                     class=\"btn btn-sm btn-info btn-icon\" title=\"";
  670.         // line 468
  671.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("productInfo"), "html"nulltrue);
  672.         yield "\">
  673.                                                 <i class=\"fas fa-info-circle\"></i>
  674.                                             </button>
  675.                                         </td>
  676.                                         <td class=\"product-select-cell\">
  677.                                             <select id=\"productselect\" class=\"form form-control\">
  678.                                                 <option value=\"\">";
  679.         // line 474
  680.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("selectWarehouseFirst"), "html"nulltrue);
  681.         yield "</option>
  682.                                             </select>
  683.                                         </td>
  684.                                         <td>
  685.                                             <div class=\"input-group input-group-sm\" style=\"max-width: 220px;\">
  686.                                                 <input type=\"text\" id=\"adder-allocated-quantity\" class=\"form-control\" value=\"0\" min=\"0\">
  687.                                                 <div class=\"input-group-append\">
  688.                                                     <select id=\"adder-quantity-unit-select\" class=\"custom-select custom-select-sm\">
  689.                                                         <option value=\"\">-</option>
  690.                                                     </select>
  691.                                                 </div>
  692.                                             </div>
  693.                                         </td>
  694.                                         <td><input type=\"text\" id=\"adder-price\" value=\"0\" min=\"0\"
  695.                                                    class=\"form-control form-control-sm price-mask\" placeholder=\"Fiyat\">
  696.                                         </td>
  697.                                         <td>
  698.                                             <select name=\"adder-discount-select\" id=\"adder-discount-select\"
  699.                                                     class=\"form-control form-control-sm\">
  700.                                                 <option value=\"0\">% 0</option>
  701.                                                 <option value=\"1\">% 1</option>
  702.                                                 <option value=\"2\">% 2</option>
  703.                                                 <option value=\"3\">% 3</option>
  704.                                                 <option value=\"4\">% 4</option>
  705.                                                 <option value=\"5\">% 5</option>
  706.                                                 <option value=\"20\">% 20</option>
  707.                                                 <option value=\"30\">% 30</option>
  708.                                                 <option value=\"100\">% 100</option>
  709.                                             </select>
  710.                                         </td>
  711.                                         <td>
  712.                                             <select name=\"adder-tva-select\" id=\"adder-tva-select\"
  713.                                                     class=\"form-control form-control-sm\">
  714.                                                 <option value=\"0\" disabled>% 0</option>
  715.                                                 <option value=\"10\">% 10</option>
  716.                                                 <option value=\"20\">% 20</option>
  717.                                             </select>
  718.                                         </td>
  719.                                         <td class=\"text-right font-weight-bold small\">
  720.                                             <input name=\"adder-total\" id=\"adder-total\" type=\"number\"
  721.                                                    class=\"form-control form-control-sm\"
  722.                                                    placeholder=\"";
  723.         // line 515
  724.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("total", [], "messages");
  725.         yield "\"/>
  726.                                         </td>
  727.                                         <td class=\"text-center\">
  728.                                             <div class=\"btn-group\" role=\"group\">
  729.                                                 <button type=\"button\" id=\"open-unallocated-modal\" class=\"btn btn-outline-secondary btn-sm\" title=\"";
  730.         // line 520
  731.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("unAllocatedQuantity", [], "messages");
  732.         yield "\">
  733.                                                     <i class=\"fas fa-box-open\"></i>
  734.                                                     <span id=\"unalloc-display\" class=\"badge badge-light ml-1\">0</span>
  735.                                                 </button>
  736.                                                 <button type=\"button\" id=\"add-product-row-btn\"
  737.                                                         class=\"btn btn-sm btn-success btn-icon\">
  738.                                                     <i class=\"fas fa-plus\"></i>
  739.                                                 </button>
  740.                                             </div>
  741.                                             <input type=\"number\" id=\"adder-unallocated-quantity\" class=\"form-control d-none\" value=\"0\" min=\"0\">
  742.                                             <select id=\"adder-unallocated-quantity-unit-select\" class=\"custom-select custom-select-sm d-none\">
  743.                                                 <option value=\"\">-</option>
  744.                                             </select>
  745.                                         </td>
  746.                                     </tr>
  747.                                     <tr id=\"info-details-row\">
  748.                                         <td colspan=\"8\" style=\"padding: 0; border-top: none;\">
  749.                                             <div id=\"info-details-content\" class=\"p-3\" style=\"display: none;\">
  750.                                             </div>
  751.                                         </td>
  752.                                     </tr>
  753.                                     </tbody>
  754.                                     <tfoot>
  755.                                         <!-- Rows will be injected by updateTotalAmounts() -->
  756.                                         <tr class=\"summary-row-placeholder\">
  757.                                             <td colspan=\"8\"></td>
  758.                                         </tr>
  759.                                     </tfoot>
  760.                                 </table>
  761.                             </div>
  762.                         </div>
  763.                     </div>
  764.                     ";
  765.         // line 553
  766.         yield         $this->env->getRuntime('Symfony\Component\Form\FormRenderer')->renderBlock((isset($context["form"]) || array_key_exists("form"$context) ? $context["form"] : (function () { throw new RuntimeError('Variable "form" does not exist.'553$this->source); })()), 'form_end');
  767.         yield "
  768.                 </div>
  769.             </div>
  770.         </div>
  771.     </div>
  772.     <div class=\"modal fade\" id=\"add-customer-modal\" role=\"dialog\" aria-labelledby=\"customerModalLabel\" aria-hidden=\"true\">
  773.         <div class=\"modal-dialog\" role=\"document\">
  774.             <div class=\"modal-content\">
  775.                 <div class=\"modal-header\">
  776.                     <h5 class=\"modal-title\" id=\"customerModalLabel\">";
  777.         // line 563
  778.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("addCustomer", [], "messages");
  779.         yield "</h5>
  780.                     <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\">
  781.                         <span aria-hidden=\"true\">&times;</span>
  782.                     </button>
  783.                 </div>
  784.                 ";
  785.         // line 568
  786.         yield         $this->env->getRuntime('Symfony\Component\Form\FormRenderer')->renderBlock((isset($context["customerForm"]) || array_key_exists("customerForm"$context) ? $context["customerForm"] : (function () { throw new RuntimeError('Variable "customerForm" does not exist.'568$this->source); })()), 'form_start');
  787.         yield "
  788.                 <div class=\"modal-body\">
  789.                     ";
  790.         // line 570
  791.         yield $this->env->getRuntime('Symfony\Component\Form\FormRenderer')->searchAndRenderBlock((isset($context["customerForm"]) || array_key_exists("customerForm"$context) ? $context["customerForm"] : (function () { throw new RuntimeError('Variable "customerForm" does not exist.'570$this->source); })()), 'widget');
  792.         yield "
  793.                 </div>
  794.                 <div class=\"modal-footer\">
  795.                     <button type=\"button\" class=\"btn btn-secondary\" data-dismiss=\"modal\">";
  796.         // line 573
  797.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("cancel", [], "messages");
  798.         yield "</button>
  799.                     <button type=\"submit\" id=\"btn-customer-save\" class=\"btn btn-primary\">";
  800.         // line 574
  801.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("save", [], "messages");
  802.         yield "</button>
  803.                 </div>
  804.                 ";
  805.         // line 576
  806.         yield         $this->env->getRuntime('Symfony\Component\Form\FormRenderer')->renderBlock((isset($context["customerForm"]) || array_key_exists("customerForm"$context) ? $context["customerForm"] : (function () { throw new RuntimeError('Variable "customerForm" does not exist.'576$this->source); })()), 'form_end');
  807.         yield "
  808.             </div>
  809.         </div>
  810.     </div>
  811.     <div class=\"modal fade\" id=\"unallocatedModal\" tabindex=\"-1\" role=\"dialog\" aria-labelledby=\"unallocatedModalLabel\" aria-hidden=\"true\">
  812.         <div class=\"modal-dialog\" role=\"document\">
  813.             <div class=\"modal-content\">
  814.                 <div class=\"modal-header\">
  815.                     <h5 class=\"modal-title\" id=\"unallocatedModalLabel\">";
  816.         // line 585
  817.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("unAllocatedQuantity", [], "messages");
  818.         yield "</h5>
  819.                     <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\">
  820.                         <span aria-hidden=\"true\">&times;</span>
  821.                     </button>
  822.                 </div>
  823.                 <div class=\"modal-body\">
  824.                     <div class=\"form-group\">
  825.                         <label for=\"modal-unallocated-quantity\">";
  826.         // line 592
  827.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("quantity", [], "messages");
  828.         yield "</label>
  829.                         <input type=\"text\" id=\"modal-unallocated-quantity\" class=\"form-control mask-money\" value=\"0\">
  830.                     </div>
  831.                     <div class=\"form-group\">
  832.                         <label for=\"modal-unallocated-unit\">";
  833.         // line 596
  834.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("unit", [], "messages");
  835.         yield "</label>
  836.                         <select id=\"modal-unallocated-unit\" class=\"custom-select\">
  837.                             <option value=\"\">-</option>
  838.                         </select>
  839.                     </div>
  840.                 </div>
  841.                 <div class=\"modal-footer\">
  842.                     <button type=\"button\" class=\"btn btn-secondary\" data-dismiss=\"modal\">";
  843.         // line 603
  844.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("close", [], "messages");
  845.         yield "</button>
  846.                     <button type=\"button\" id=\"save-unallocated-btn\" class=\"btn btn-primary\">";
  847.         // line 604
  848.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("save", [], "messages");
  849.         yield "</button>
  850.                 </div>
  851.             </div>
  852.         </div>
  853.     </div>
  854.     <div class=\"modal fade\" id=\"add-payment-modal\" role=\"dialog\" aria-labelledby=\"paymentModalLabel\" aria-hidden=\"true\">
  855.         <div class=\"modal-dialog\" role=\"document\">
  856.             <div class=\"modal-content\">
  857.                 <div class=\"modal-header\">
  858.                     <h5 class=\"modal-title\" id=\"paymentModalLabel\">";
  859.         // line 614
  860.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("addPayment", [], "messages");
  861.         yield "</h5>
  862.                     <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\">
  863.                         <span aria-hidden=\"true\">&times;</span>
  864.                     </button>
  865.                 </div>
  866.                 <div class=\"modal-body\">
  867.                     ";
  868.         // line 620
  869.         yield $this->env->getRuntime('Symfony\Component\Form\FormRenderer')->searchAndRenderBlock((isset($context["paymentForm"]) || array_key_exists("paymentForm"$context) ? $context["paymentForm"] : (function () { throw new RuntimeError('Variable "paymentForm" does not exist.'620$this->source); })()), 'widget');
  870.         yield "
  871.                     ";
  872.         // line 621
  873.         yield         $this->env->getRuntime('Symfony\Component\Form\FormRenderer')->renderBlock((isset($context["paymentForm"]) || array_key_exists("paymentForm"$context) ? $context["paymentForm"] : (function () { throw new RuntimeError('Variable "paymentForm" does not exist.'621$this->source); })()), 'form_start');
  874.         yield "
  875.                     ";
  876.         // line 622
  877.         yield         $this->env->getRuntime('Symfony\Component\Form\FormRenderer')->renderBlock((isset($context["paymentForm"]) || array_key_exists("paymentForm"$context) ? $context["paymentForm"] : (function () { throw new RuntimeError('Variable "paymentForm" does not exist.'622$this->source); })()), 'form_end');
  878.         yield "
  879.                 </div>
  880.                 <div class=\"modal-footer\">
  881.                     <button type=\"button\" class=\"btn btn-secondary\" data-dismiss=\"modal\">";
  882.         // line 625
  883.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("cancel", [], "messages");
  884.         yield "</button>
  885.                     <button type=\"button\" id=\"save-payment-btn\" class=\"btn btn-primary\">";
  886.         // line 626
  887.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("save", [], "messages");
  888.         yield "</button>
  889.                 </div>
  890.             </div>
  891.         </div>
  892.     </div>
  893.     <div class=\"modal fade\" id=\"updateCustomerModal\" tabindex=\"-1\" role=\"dialog\" aria-labelledby=\"updateModalLabel\" aria-hidden=\"true\">
  894.         <div class=\"modal-dialog\" role=\"document\">
  895.             <div class=\"modal-content\">
  896.                 <div class=\"modal-header\">
  897.                     <h5 class=\"modal-title\" id=\"updateModalLabel\">";
  898.         // line 636
  899.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("updateCustomerInfoMessage", [], "messages");
  900.         yield "</h5>
  901.                     <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\">
  902.                         <span aria-hidden=\"true\">&times;</span>
  903.                     </button>
  904.                 </div>
  905.                 <form id=\"updateCustomerForm\">
  906.                     <div class=\"modal-body\">
  907.                         <input type=\"hidden\" id=\"update_customer_id\">
  908.                         <div class=\"form-group\">
  909.                             <label for=\"update_customer_fullName\">";
  910.         // line 645
  911.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("fullName", [], "messages");
  912.         yield "</label>
  913.                             <input type=\"text\" class=\"form-control\" id=\"update_customer_fullName\" required>
  914.                         </div>
  915.                         <div class=\"form-group\">
  916.                             <label for=\"update_customer_email\">";
  917.         // line 649
  918.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("email", [], "messages");
  919.         yield "</label>
  920.                             <input type=\"email\" class=\"form-control\" id=\"update_customer_email\">
  921.                         </div>
  922.                         <div class=\"form-group\">
  923.                             <label for=\"update_customer_phone\">";
  924.         // line 653
  925.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("phone", [], "messages");
  926.         yield "</label>
  927.                             <input type=\"text\" class=\"form-control\" id=\"update_customer_phone\">
  928.                         </div>
  929.                         <div class=\"form-group\">
  930.                             <label for=\"update_customer_address\">";
  931.         // line 657
  932.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("address", [], "messages");
  933.         yield "</label>
  934.                             <textarea class=\"form-control\" id=\"update_customer_address\" rows=\"3\"></textarea>
  935.                         </div>
  936.                     </div>
  937.                     <div class=\"modal-footer\">
  938.                         <button type=\"button\" class=\"btn btn-secondary\" data-dismiss=\"modal\">";
  939.         // line 662
  940.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("close", [], "messages");
  941.         yield "</button>
  942.                         <button type=\"submit\" class=\"btn btn-primary\">";
  943.         // line 663
  944.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("save", [], "messages");
  945.         yield "</button>
  946.                     </div>
  947.                 </form>
  948.             </div>
  949.         </div>
  950.     </div>
  951.     <div class=\"modal fade\" id=\"updateServiceModal\" tabindex=\"-1\" role=\"dialog\" aria-labelledby=\"updateServiceModalLabel\" aria-hidden=\"true\">
  952.         <div class=\"modal-dialog\" role=\"document\">
  953.             <div class=\"modal-content\">
  954.                 <div class=\"modal-header\">
  955.                     <h5 class=\"modal-title\" id=\"updateServiceModalLabel\">";
  956.         // line 675
  957.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("updateServiceInfoMessage", [], "messages");
  958.         yield "</h5>
  959.                     <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\">
  960.                         <span aria-hidden=\"true\">&times;</span>
  961.                     </button>
  962.                 </div>
  963.                 <form id=\"updateServiceForm\" onsubmit=\"return false;\">
  964.                     <div class=\"modal-body\">
  965.                         <input type=\"hidden\" id=\"update_service_id\">
  966.                         <div class=\"form-group\">
  967.                             <label for=\"update_service_name\">";
  968.         // line 684
  969.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("serviceName", [], "messages");
  970.         yield "</label>
  971.                             <input type=\"text\" class=\"form-control\" id=\"update_service_name\">
  972.                         </div>
  973.                         <div class=\"form-group\">
  974.                             <label for=\"update_service_cost\">";
  975.         // line 688
  976.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("cost", [], "messages");
  977.         yield "</label>
  978.                             <input type=\"text\" value=\"0.00\" class=\"form-control mask-money\" id=\"update_service_cost\" required>
  979.                         </div>
  980.                         <div class=\"form-group\">
  981.                             <label for=\"update_service_description\">";
  982.         // line 693
  983.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("description", [], "messages");
  984.         yield "</label>
  985.                             <input type=\"text\" class=\"form-control\" id=\"update_service_description\">
  986.                         </div>
  987.                     </div>
  988.                     <div class=\"modal-footer\">
  989.                         <button type=\"button\" class=\"btn btn-secondary\" data-dismiss=\"modal\">";
  990.         // line 698
  991.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("close", [], "messages");
  992.         yield "</button>
  993.                         <button type=\"button\" class=\"btn btn-primary\" id=\"service_modal_save_changes_btn\">";
  994.         // line 699
  995.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("save", [], "messages");
  996.         yield "</button>
  997.                     </div>
  998.                 </form>
  999.             </div>
  1000.         </div>
  1001.     </div>
  1002.     <div class=\"modal fade\" id=\"autoPaymentModal\" tabindex=\"-1\" role=\"dialog\" aria-labelledby=\"autoPaymentModalLabel\" aria-hidden=\"true\">
  1003.         <div class=\"modal-dialog modal-dialog-centered\" role=\"document\">
  1004.             <div class=\"modal-content\">
  1005.                 <div class=\"modal-header\">
  1006.                     <h5 class=\"modal-title\" id=\"autoPaymentModalLabel\">";
  1007.         // line 710
  1008.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("autoPaymentConfirmation"), "html"nulltrue);
  1009.         yield "</h5>
  1010.                     <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\">
  1011.                         <span aria-hidden=\"true\">&times;</span>
  1012.                     </button>
  1013.                 </div>
  1014.                 <div class=\"modal-body\">
  1015.                     <p id=\"auto-payment-message\" class=\"mb-3\"></p>
  1016.                     <div class=\"border rounded px-3 py-2 bg-light\">
  1017.                         <div class=\"d-flex justify-content-between\"><span>";
  1018.         // line 718
  1019.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("salesTotal"), "html"nulltrue);
  1020.         yield "</span><span id=\"auto-payment-sale-total\">0,00 ";
  1021.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("currency.symbol"), "html"nulltrue);
  1022.         yield "</span></div>
  1023.                         <div class=\"d-flex justify-content-between\"><span>";
  1024.         // line 719
  1025.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("currentPayments"), "html"nulltrue);
  1026.         yield "</span><span id=\"auto-payment-current-payments\">0,00 ";
  1027.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("currency.symbol"), "html"nulltrue);
  1028.         yield "</span></div>
  1029.                         <div class=\"d-flex justify-content-between font-weight-bold\"><span>";
  1030.         // line 720
  1031.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("paymentToAdd"), "html"nulltrue);
  1032.         yield "</span><span id=\"auto-payment-amount\">0,00 ";
  1033.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("currency.symbol"), "html"nulltrue);
  1034.         yield "</span></div>
  1035.                         <hr>
  1036.                         <div class=\"small\">
  1037.                             <div><strong>";
  1038.         // line 723
  1039.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("paymentStatusLabel"), "html"nulltrue);
  1040.         yield ":</strong> <span id=\"auto-payment-status\"></span></div>
  1041.                             <div><strong>";
  1042.         // line 724
  1043.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("paymentTypeLabel"), "html"nulltrue);
  1044.         yield ":</strong> <span id=\"auto-payment-method\"></span></div>
  1045.                             <div><strong>";
  1046.         // line 725
  1047.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("description"), "html"nulltrue);
  1048.         yield ":</strong> <span id=\"auto-payment-description\"></span></div>
  1049.                         </div>
  1050.                     </div>
  1051.                 </div>
  1052.                 <div class=\"modal-footer\">
  1053.                     <button type=\"button\" class=\"btn btn-secondary\" data-dismiss=\"modal\">";
  1054.         // line 730
  1055.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("cancel"), "html"nulltrue);
  1056.         yield "</button>
  1057.                     <button type=\"button\" class=\"btn btn-primary\" id=\"confirm-auto-payment\">";
  1058.         // line 731
  1059.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("confirmAction"), "html"nulltrue);
  1060.         yield "</button>
  1061.                 </div>
  1062.             </div>
  1063.         </div>
  1064.     </div>
  1065.     <!-- Hediye Çeki Kullanım Modalı -->
  1066.     <div class=\"modal fade\" id=\"gift-voucher-usage-modal\" tabindex=\"-1\" role=\"dialog\" aria-labelledby=\"giftVoucherUsageModalLabel\" aria-hidden=\"true\">
  1067.         <div class=\"modal-dialog modal-dialog-centered\" role=\"document\">
  1068.             <div class=\"modal-content\">
  1069.                 <div class=\"modal-header\">
  1070.                     <h5 class=\"modal-title\" id=\"giftVoucherUsageModalLabel\">";
  1071.         // line 742
  1072.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("giftVoucherUsage"), "html"nulltrue);
  1073.         yield "</h5>
  1074.                     <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\">
  1075.                         <span aria-hidden=\"true\">&times;</span>
  1076.                     </button>
  1077.                 </div>
  1078.                 <div class=\"modal-body\">
  1079.                     <div class=\"alert alert-info\">
  1080.                         <strong><span id=\"voucher-customer-name\"></span></strong>";
  1081.         // line 749
  1082.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("voucherBalanceInfoSuffix"), "html"nulltrue);
  1083.         yield ": <strong id=\"voucher-total-balance\">0.00 TL</strong>
  1084.                     </div>
  1085.                     <div class=\"form-group\">
  1086.                         <label for=\"voucher-use-amount\">";
  1087.         // line 752
  1088.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("amountToUse"), "html"nulltrue);
  1089.         yield "</label>
  1090.                         <input type=\"number\" id=\"voucher-use-amount\" class=\"form-control\" placeholder=\"0.00\" min=\"0\" step=\"0.01\">
  1091.                         <small class=\"form-text text-muted\">";
  1092.         // line 754
  1093.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("enterAmountToUse"), "html"nulltrue);
  1094.         yield "</small>
  1095.                     </div>
  1096.                 </div>
  1097.                 <div class=\"modal-footer\">
  1098.                     <button type=\"button\" class=\"btn btn-secondary\" data-dismiss=\"modal\">";
  1099.         // line 758
  1100.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("cancel"), "html"nulltrue);
  1101.         yield "</button>
  1102.                     <button type=\"button\" class=\"btn btn-primary\" id=\"btn-confirm-voucher-usage\">";
  1103.         // line 759
  1104.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("confirmAndAdd"), "html"nulltrue);
  1105.         yield "</button>
  1106.                 </div>
  1107.             </div>
  1108.         </div>
  1109.     </div>
  1110. ";
  1111.         
  1112.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  1113.         
  1114.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  1115.         yield from [];
  1116.     }
  1117.     // line 767
  1118.     /**
  1119.      * @return iterable<null|scalar|\Stringable>
  1120.      */
  1121.     public function block_javascript(array $context, array $blocks = []): iterable
  1122.     {
  1123.         $macros $this->macros;
  1124.         $__internal_5a27a8ba21ca79b61932376b2fa922d2 $this->extensions["Symfony\\Bundle\\WebProfilerBundle\\Twig\\WebProfilerExtension"];
  1125.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->enter($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""javascript"));
  1126.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f $this->extensions["Symfony\\Bridge\\Twig\\Extension\\ProfilerExtension"];
  1127.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->enter($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof = new \Twig\Profiler\Profile($this->getTemplateName(), "block""javascript"));
  1128.         // line 768
  1129.         yield "<script src=\"";
  1130.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\AssetExtension']->getAssetUrl("/decimal.js"), "html"nulltrue);
  1131.         yield "\"></script>
  1132.     <script>
  1133.         document.addEventListener('DOMContentLoaded', () => {
  1134.             const saleDateInput = document.getElementById('sales_form_salesDate');
  1135.             if (saleDateInput && !saleDateInput.value) {
  1136.                 const now = new Date();
  1137.                 const localDate = new Date(now.getTime() - now.getTimezoneOffset() * 60000).toISOString().split('T')[0];
  1138.                 saleDateInput.value = localDate;
  1139.                 saleDateInput.dispatchEvent(new Event('change', { bubbles: true }));
  1140.             }
  1141.         });
  1142.         \$(document).ready(function() {
  1143.             applyMasks();
  1144.             const isDuplicatedProforma = ";
  1145.         // line 783
  1146.         yield (((array_key_exists("sales"$context) &&  !(null === CoreExtension::getAttribute($this->env$this->source, (isset($context["sales"]) || array_key_exists("sales"$context) ? $context["sales"] : (function () { throw new RuntimeError('Variable "sales" does not exist.'783$this->source); })()), "id", [], "any"falsefalsefalse783)))) ? ("true") : ("false"));
  1147.         yield ";
  1148.             const duplicatedSoldItems = (function(){
  1149.                 if(!isDuplicatedProforma){ return []; }
  1150.                 const items = [];
  1151.                 ";
  1152.         // line 788
  1153.         if ((array_key_exists("sales"$context) && CoreExtension::getAttribute($this->env$this->source, ($context["sales"] ?? null), "productsSolds", [], "any"truetruefalse788))) {
  1154.             // line 789
  1155.             yield "                    ";
  1156.             $context['_parent'] = $context;
  1157.             $context['_seq'] = CoreExtension::ensureTraversable(CoreExtension::getAttribute($this->env$this->source, (isset($context["sales"]) || array_key_exists("sales"$context) ? $context["sales"] : (function () { throw new RuntimeError('Variable "sales" does not exist.'789$this->source); })()), "productsSolds", [], "any"falsefalsefalse789));
  1158.             foreach ($context['_seq'] as $context["_key"] => $context["ps"]) {
  1159.                 // line 790
  1160.                 yield "                        items.push({
  1161.                             productid: ";
  1162.                 // line 791
  1163.                 yield (((($tmp CoreExtension::getAttribute($this->env$this->source$context["ps"], "product", [], "any"falsefalsefalse791)) && $tmp instanceof Markup ? (string) $tmp $tmp)) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source$context["ps"], "product", [], "any"falsefalsefalse791), "id", [], "any"falsefalsefalse791), "html"nulltrue)) : (0));
  1164.                 yield ",
  1165.                             productName: '";
  1166.                 // line 792
  1167.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(((CoreExtension::getAttribute($this->env$this->source$context["ps"], "productName", [], "any"truetruefalse792)) ? (Twig\Extension\CoreExtension::default(CoreExtension::getAttribute($this->env$this->source$context["ps"], "productName", [], "any"falsefalsefalse792), (((($tmp CoreExtension::getAttribute($this->env$this->source$context["ps"], "product", [], "any"falsefalsefalse792)) && $tmp instanceof Markup ? (string) $tmp $tmp)) ? (CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source$context["ps"], "product", [], "any"falsefalsefalse792), "name", [], "any"falsefalsefalse792)) : ("")))) : ((((($tmp CoreExtension::getAttribute($this->env$this->source$context["ps"], "product", [], "any"falsefalsefalse792)) && $tmp instanceof Markup ? (string) $tmp $tmp)) ? (CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source$context["ps"], "product", [], "any"falsefalsefalse792), "name", [], "any"falsefalsefalse792)) : ("")))), "js"), "html"nulltrue);
  1168.                 yield "',
  1169.                             code: '";
  1170.                 // line 793
  1171.                 yield (((($tmp CoreExtension::getAttribute($this->env$this->source$context["ps"], "product", [], "any"falsefalsefalse793)) && $tmp instanceof Markup ? (string) $tmp $tmp)) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source$context["ps"], "product", [], "any"falsefalsefalse793), "code", [], "any"falsefalsefalse793), "js"), "html"nulltrue)) : (""));
  1172.                 yield "',
  1173.                             measurement: '";
  1174.                 // line 794
  1175.                 yield (((($tmp =  !(null === CoreExtension::getAttribute($this->env$this->source$context["ps"], "measurement", [], "any"falsefalsefalse794))) && $tmp instanceof Markup ? (string) $tmp $tmp)) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["ps"], "measurement", [], "any"falsefalsefalse794), "js"), "html"nulltrue)) : ((((CoreExtension::getAttribute($this->env$this->source$context["ps"], "product", [], "any"falsefalsefalse794) && CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source$context["ps"], "product", [], "any"falsefalsefalse794), "measurement", [], "any"falsefalsefalse794))) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source$context["ps"], "product", [], "any"falsefalsefalse794), "measurement", [], "any"falsefalsefalse794), "name", [], "any"falsefalsefalse794), "js"), "html"nulltrue)) : (""))));
  1176.                 yield "',
  1177.                             quantity: ";
  1178.                 // line 795
  1179.                 yield (((($tmp =  !(null === CoreExtension::getAttribute($this->env$this->source$context["ps"], "quantity", [], "any"falsefalsefalse795))) && $tmp instanceof Markup ? (string) $tmp $tmp)) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatNumber(CoreExtension::getAttribute($this->env$this->source$context["ps"], "quantity", [], "any"falsefalsefalse795), 2"."""), "html"nulltrue)) : ("0"));
  1180.                 yield ",
  1181.                             unAllocatedQuantity: ";
  1182.                 // line 796
  1183.                 yield (((($tmp =  !(null === CoreExtension::getAttribute($this->env$this->source$context["ps"], "unAllocatedQuantity", [], "any"falsefalsefalse796))) && $tmp instanceof Markup ? (string) $tmp $tmp)) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatNumber(CoreExtension::getAttribute($this->env$this->source$context["ps"], "unAllocatedQuantity", [], "any"falsefalsefalse796), 2"."""), "html"nulltrue)) : ("0"));
  1184.                 yield ",
  1185.                             unitPrice: ";
  1186.                 // line 797
  1187.                 yield (((($tmp =  !(null === CoreExtension::getAttribute($this->env$this->source$context["ps"], "totalUnitPurchasePrice", [], "any"falsefalsefalse797))) && $tmp instanceof Markup ? (string) $tmp $tmp)) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatNumber(CoreExtension::getAttribute($this->env$this->source$context["ps"], "totalUnitPurchasePrice", [], "any"falsefalsefalse797), 2"."""), "html"nulltrue)) : ("0"));
  1188.                 yield ",
  1189.                             tax: ";
  1190.                 // line 798
  1191.                 yield (((($tmp =  !(null === CoreExtension::getAttribute($this->env$this->source$context["ps"], "tax", [], "any"falsefalsefalse798))) && $tmp instanceof Markup ? (string) $tmp $tmp)) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatNumber(CoreExtension::getAttribute($this->env$this->source$context["ps"], "tax", [], "any"falsefalsefalse798), 2"."""), "html"nulltrue)) : ("0"));
  1192.                 yield ",
  1193.                             discount: ";
  1194.                 // line 799
  1195.                 yield (((($tmp =  !(null === CoreExtension::getAttribute($this->env$this->source$context["ps"], "discount", [], "any"falsefalsefalse799))) && $tmp instanceof Markup ? (string) $tmp $tmp)) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatNumber(CoreExtension::getAttribute($this->env$this->source$context["ps"], "discount", [], "any"falsefalsefalse799), 2"."""), "html"nulltrue)) : ("0"));
  1196.                 yield ",
  1197.                             totalPurchasePrice: ";
  1198.                 // line 800
  1199.                 yield (((($tmp =  !(null === CoreExtension::getAttribute($this->env$this->source$context["ps"], "totalPuchasePrice", [], "any"falsefalsefalse800))) && $tmp instanceof Markup ? (string) $tmp $tmp)) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatNumber(CoreExtension::getAttribute($this->env$this->source$context["ps"], "totalPuchasePrice", [], "any"falsefalsefalse800), 2"."""), "html"nulltrue)) : ((((($tmp =  !(null === CoreExtension::getAttribute($this->env$this->source$context["ps"], "totalPuchasePrice", [], "any"falsefalsefalse800))) && $tmp instanceof Markup ? (string) $tmp $tmp)) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatNumber(CoreExtension::getAttribute($this->env$this->source$context["ps"], "totalPuchasePrice", [], "any"falsefalsefalse800), 2"."""), "html"nulltrue)) : ((((($tmp =  !(null === CoreExtension::getAttribute($this->env$this->source$context["ps"], "totalPrice", [], "any"falsefalsefalse800))) && $tmp instanceof Markup ? (string) $tmp $tmp)) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Twig\Extension\CoreExtension']->formatNumber(CoreExtension::getAttribute($this->env$this->source$context["ps"], "totalPrice", [], "any"falsefalsefalse800), 2"."""), "html"nulltrue)) : ("0"))))));
  1200.                 yield ",
  1201.                             totalPrice: ";
  1202.                 // line 801
  1203.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["ps"], "totalPrice", [], "any"falsefalsefalse801), "html"nulltrue);
  1204.                 yield ",
  1205.                             warehouse: ";
  1206.                 // line 802
  1207.                 yield (((($tmp CoreExtension::getAttribute($this->env$this->source, (isset($context["sales"]) || array_key_exists("sales"$context) ? $context["sales"] : (function () { throw new RuntimeError('Variable "sales" does not exist.'802$this->source); })()), "warehouse", [], "any"falsefalsefalse802)) && $tmp instanceof Markup ? (string) $tmp $tmp)) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source, (isset($context["sales"]) || array_key_exists("sales"$context) ? $context["sales"] : (function () { throw new RuntimeError('Variable "sales" does not exist.'802$this->source); })()), "warehouse", [], "any"falsefalsefalse802), "id", [], "any"falsefalsefalse802), "html"nulltrue)) : (0));
  1208.                 yield ",
  1209.                             thickness: 0,
  1210.                             width: 0,
  1211.                             height: 0,
  1212.                             cost: 0,
  1213.                             productType: '";
  1214.                 // line 807
  1215.                 yield (((CoreExtension::getAttribute($this->env$this->source$context["ps"], "product", [], "any"falsefalsefalse807) && CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source$context["ps"], "product", [], "any"falsefalsefalse807), "productTypeEnum", [], "any"falsefalsefalse807))) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source$context["ps"], "product", [], "any"falsefalsefalse807), "productTypeEnum", [], "any"falsefalsefalse807), "name", [], "any"falsefalsefalse807), "js"), "html"nulltrue)) : (""));
  1216.                 yield "',
  1217.                             selectedUnitId: ";
  1218.                 // line 808
  1219.                 yield (((($tmp CoreExtension::getAttribute($this->env$this->source$context["ps"], "selectedUnit", [], "any"falsefalsefalse808)) && $tmp instanceof Markup ? (string) $tmp $tmp)) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source$context["ps"], "selectedUnit", [], "any"falsefalsefalse808), "id", [], "any"falsefalsefalse808), "html"nulltrue)) : ("null"));
  1220.                 yield "
  1221.                         });
  1222.                     ";
  1223.             }
  1224.             $_parent $context['_parent'];
  1225.             unset($context['_seq'], $context['_key'], $context['ps'], $context['_parent']);
  1226.             $context array_intersect_key($context$_parent) + $_parent;
  1227.             // line 811
  1228.             yield "                ";
  1229.         }
  1230.         // line 812
  1231.         yield "                return items;
  1232.             })();
  1233.             // TODO: Duplicated items
  1234.             async function importDuplicatedSoldItemsIfNeeded(){
  1235.                 await getProductsFromWarehouse();
  1236.                 if(!isDuplicatedProforma || duplicatedSoldItems.length === 0){
  1237.                     return;
  1238.                 }
  1239.                 const targetWarehouseId = ";
  1240.         // line 820
  1241.         yield (((array_key_exists("sales"$context) && CoreExtension::getAttribute($this->env$this->source, (isset($context["sales"]) || array_key_exists("sales"$context) ? $context["sales"] : (function () { throw new RuntimeError('Variable "sales" does not exist.'820$this->source); })()), "warehouse", [], "any"falsefalsefalse820))) ? ($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->sourceCoreExtension::getAttribute($this->env$this->source, (isset($context["sales"]) || array_key_exists("sales"$context) ? $context["sales"] : (function () { throw new RuntimeError('Variable "sales" does not exist.'820$this->source); })()), "warehouse", [], "any"falsefalsefalse820), "id", [], "any"falsefalsefalse820), "html"nulltrue)) : (0));
  1242.         yield ";
  1243.                 if(targetWarehouseId){
  1244.                     \$('#warehouseselect').val(String(targetWarehouseId));
  1245.                     \$('#warehouseselect').trigger('change');
  1246.                 }
  1247.                 const start = Date.now();
  1248.                 const timeoutMs = 15000;
  1249.                 const timer = setInterval(function(){
  1250.                     if(Array.isArray(products) && products.length > 0){
  1251.                         clearInterval(timer);
  1252.                         try{
  1253.                             duplicatedSoldItems.forEach(function(item){
  1254.                                 const p = products.find(function(prod){ return prod.productid === item.productid; });
  1255.                                 if(p){
  1256.                                     selectProduct(p.productid);
  1257.                                 }
  1258.                                 addProductToSoldList(
  1259.                                     item.productid,
  1260.                                     item.productName,
  1261.                                     item.code,
  1262.                                     item.measurement,
  1263.                                     item.quantity,
  1264.                                     item.unitPrice,
  1265.                                     item.tax,
  1266.                                     item.discount,
  1267.                                     item.totalPurchasePrice,
  1268.                                     item.warehouse,
  1269.                                     item.unAllocatedQuantity,
  1270.                                     item.thickness,
  1271.                                     item.width,
  1272.                                     item.height,
  1273.                                     item.cost,
  1274.                                     item.productType,
  1275.                                     item.selectedUnitId
  1276.                                 );
  1277.                             });
  1278.                             fetchSoldListRows();
  1279.                             updateTotalAmounts();
  1280.                             \$('#sales_form_totalPurchasePrice').val(addCommas(getTotalSoldAmount()));
  1281.                             fetchPaymentForm();
  1282.                             fetchStocks();
  1283.                         }catch(e){
  1284.                             console.error('Duplicate import error', e);
  1285.                         }
  1286.                     }else if(Date.now() - start > timeoutMs){
  1287.                         clearInterval(timer);
  1288.                         console.warn('Timed out waiting for products to load');
  1289.                     }
  1290.                 }, 200);
  1291.             }
  1292.             if(isDuplicatedProforma){
  1293.                 importDuplicatedSoldItemsIfNeeded();
  1294.             }
  1295.             // =============================================================================
  1296.             // INITIALIZATION & GLOBAL VARIABLES
  1297.             // =============================================================================
  1298.             // Collapse sidebar only on this page
  1299.             \$('body').addClass('sidebar-toggled');
  1300.             \$('#accordionSidebar').addClass('toggled');
  1301.             // Product data structure
  1302.             let product = {
  1303.                 code: \"\",
  1304.                 id: 0,
  1305.                 length: 0,
  1306.                 measurement: \"\",
  1307.                 name: \"\",
  1308.                 priceFob: 0,
  1309.                 priceNavlun: 0,
  1310.                 productid: 0,
  1311.                 purchaseTotalAmount: 0,
  1312.                 quantity: 0,
  1313.                 thickness: 0,
  1314.                 totalQuantity: 0,
  1315.                 totalUnitPrice: 0,
  1316.                 width: 0,
  1317.                 cost: 0,
  1318.                 measurementUnit: \"\",
  1319.                 stock: 0,
  1320.                 warehouseid: 0,
  1321.                 selected: false,
  1322.             }
  1323.             let products = [];
  1324.             // Sold product data structure
  1325.             let soldProduct = {
  1326.                 productid: 0,
  1327.                 productName: \"\",
  1328.                 code: \"\",
  1329.                 measurement: \"\",
  1330.                 quantity: 0,
  1331.                 baseUnitQuantity: 0,
  1332.                 unAllocatedQuantity: 0,
  1333.                 unitPrice: 0,
  1334.                 tax: 0,
  1335.                 discount: 0,
  1336.                 totalPurchasePrice: 0,
  1337.                 warehouse: 0,
  1338.             }
  1339.             let soldList = [];
  1340.             const MONEY_ROUNDING_MODE = Decimal.ROUND_HALF_UP;
  1341.             // Payment data structure
  1342.             let payment = {
  1343.                 uuid: 0,
  1344.                 id: 0,
  1345.                 amount: 0,
  1346.                 status: 0,
  1347.                 paymentDate: new Date(),
  1348.                 paymentDueDate: new Date(),
  1349.                 paymentMethod: 0,
  1350.                 description: 0,
  1351.             }
  1352.             let payments = []
  1353.             // =============================================================================
  1354.             // UTILITY FUNCTIONS
  1355.             // =============================================================================
  1356.             
  1357.              function formatCurrency(amount) {
  1358.                 if (amount instanceof Decimal) {
  1359.                     amount = amount.toNumber();
  1360.                 }
  1361.                 return addCommas(amount.toFixed(2)) + ' ";
  1362.         // line 949
  1363.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("currency.symbol"), "html"nulltrue);
  1364.         yield "';
  1365.             }
  1366.             // Convert entered quantity in selected unit to product base unit quantity
  1367.             function computeBaseUnitQuantity(productId, selectedUnitId, quantity, onDone){
  1368.                 try{
  1369.                     const product = products.find(p => p.productid === productId);
  1370.                     if(!product){ onDone(quantity); return; }
  1371.                     // If unit not selected or already base unit, fallback to same quantity
  1372.                     if(!selectedUnitId || String(selectedUnitId) === '' || String(selectedUnitId) === String(product.measurementUnitId)){
  1373.                         onDone(quantity);
  1374.                         return;
  1375.                     }
  1376.                     \$.ajax({
  1377.                         url: '/admin/measurement/convert-to-product-unit',
  1378.                         method: 'POST',
  1379.                         dataType: 'json',
  1380.                         data: {
  1381.                             productId: productId,
  1382.                             fromUnitId: selectedUnitId,
  1383.                             quantity: quantity
  1384.                         },
  1385.                         success: function(resp){
  1386.                             if(resp && resp.success){
  1387.                                 onDone(parseFloat(resp.result));
  1388.                             } else {
  1389.                                 onDone(quantity);
  1390.                             }
  1391.                         },
  1392.                         error: function(){ onDone(quantity); }
  1393.                     });
  1394.                 }catch(e){ onDone(quantity); }
  1395.             }
  1396.             // Check if product already exists in sold list with same parameters
  1397.             function issetInSoldList(productid, quantity, unitPrice, tax, discount, totalPurchasePrice) {
  1398.                 const foundProduct = soldList.find(product =>
  1399.                     product.productid === productid &&
  1400.                     product.quantity === quantity &&
  1401.                     product.unitPrice === unitPrice &&
  1402.                     product.tax === tax &&
  1403.                     product.discount === discount &&
  1404.                     product.totalPurchasePrice === totalPurchasePrice
  1405.                 );
  1406.                 return !!foundProduct;
  1407.             }
  1408.             function applyMasks() {
  1409.                 \$('.mask-money').mask(\"##0.00\", { reverse: true });
  1410.             }
  1411.             // Convert various input types to Decimal for precise calculations
  1412.             function convertToDecimal(value) {
  1413.                 try {
  1414.                     if (value instanceof Decimal) {
  1415.                         return value;
  1416.                     }
  1417.                     if (value === undefined || value === null) {
  1418.                         return new Decimal(0);
  1419.                     }
  1420.                     if (typeof value === 'number') {
  1421.                         if (!isFinite(value) || isNaN(value)) {
  1422.                             return new Decimal(0);
  1423.                         }
  1424.                         return new Decimal(value);
  1425.                     }
  1426.                     if (typeof value === 'string') {
  1427.                         var sanitized = value.replace(/[^0-9.,-]/g, '').replace(/,/g, '').trim();
  1428.                         if (sanitized === '' || sanitized === '-' || sanitized === '.' || sanitized === '-.') {
  1429.                             return new Decimal(0);
  1430.                         }
  1431.                         return new Decimal(sanitized);
  1432.                     }
  1433.                     return new Decimal(0);
  1434.                 } catch (e) {
  1435.                     return new Decimal(0);
  1436.                 }
  1437.             }
  1438.             // Round value to specified decimal places (default 2)
  1439.             function roundToDecimal(value, decimalPlaces = 2) {
  1440.                 const decimalValue = new Decimal(value);
  1441.                 const roundedValue = decimalValue.toDecimalPlaces(decimalPlaces, Decimal.ROUND_UP);
  1442.                 return roundedValue.toNumber();
  1443.             }
  1444.             // Round stock values down to prevent overselling
  1445.             function roundStockToDecimal(value, decimalPlaces = 2) {
  1446.                 const decimalValue = new Decimal(value);
  1447.                 const roundedValue = decimalValue.toDecimalPlaces(decimalPlaces, Decimal.ROUND_DOWN);
  1448.                 return roundedValue.toNumber();
  1449.             }
  1450.             // Round to nearest cent for currency calculations
  1451.             function roundToNearestCent(amount) {
  1452.                 return Math.round(amount * 100) / 100;
  1453.             }
  1454.             // Round to two decimal places
  1455.             function roundToTwoDecimals(number) {
  1456.                 var factor = Math.pow(10, 2);
  1457.                 return (Math.round(number * factor) / factor).toFixed(2);
  1458.             }
  1459.             // Validate numeric input
  1460.             function validate(s) {
  1461.                 var rgx = /^[0-9]*\\.?[0-9]*\$/;
  1462.                 return s.match(rgx);
  1463.             }
  1464.             // Convert string to float, handling commas
  1465.             function convertToFloat(value) {
  1466.                 if (typeof value === \"string\") {
  1467.                     value = value.replace(',', '');
  1468.                 }
  1469.                 return parseFloat(value);
  1470.             }
  1471.             // Add thousand separators to numbers
  1472.             function addCommas(number) {
  1473.                 let decimals = 2;
  1474.                 number = (number + '').replace(/[^0-9+\\-Ee.]/g, '');
  1475.                 var n = !isFinite(+number) ? 0 : +number;
  1476.                 var prec = !isFinite(+decimals) ? 0 : Math.abs(decimals);
  1477.                 var sep = ',';
  1478.                 var dec = '.';
  1479.                 var s = '';
  1480.                 var toFixedFix = function(n, prec) {
  1481.                     var k = Math.pow(10, prec);
  1482.                     return '' + (Math.round(n * k) / k).toFixed(prec);
  1483.                 };
  1484.                 s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.');
  1485.                 if (s[0].length > 3) {
  1486.                     s[0] = s[0].replace(/\\B(?=(?:\\d{3})+(?!\\d))/g, sep);
  1487.                 }
  1488.                 if ((s[1] || '').length < prec) {
  1489.                     s[1] = s[1] || '';
  1490.                     s[1] += new Array(prec - s[1].length + 1).join('0');
  1491.                 }
  1492.                 return s.join(dec);
  1493.             }
  1494.             // Create popup window with specified dimensions
  1495.             function createPopup(url, window_name = 'example-popup') {
  1496.                 var width = 1100;
  1497.                 var height = 700;
  1498.                 var screen_width = window.screen.width;
  1499.                 var screen_height = window.screen.height;
  1500.                 var popup_left = (screen_width - width) / 2;
  1501.                 var popup_top = (screen_height - height) / 2;
  1502.                 var popup_window = window.open(url, window_name, 'width=' + width + ',height=' + height + ',left=' + popup_left + ',top=' + popup_top);
  1503.             }
  1504.             // Show error alert using SweetAlert
  1505.             function showErrorAlert(message) {
  1506.                 Swal.fire({
  1507.                     icon: 'error',
  1508.                     title: 'Oops...',
  1509.                     text: '' + message,
  1510.                     background: 'white',
  1511.                 });
  1512.             }
  1513.             // Show success alert using SweetAlert
  1514.             function showSuccessAlert(message) {
  1515.                 Swal.fire({
  1516.                     icon: 'success',
  1517.                     title: 'Başarılı',
  1518.                     text: '' + message,
  1519.                     background: 'white',
  1520.                 });
  1521.             }
  1522.             // =============================================================================
  1523.             // PRODUCT MANAGEMENT FUNCTIONS
  1524.             // =============================================================================
  1525.             // Add product to sold list with validation
  1526.             function addProductToSoldList(
  1527.                 productid,
  1528.                 productName,
  1529.                 code,
  1530.                 measurement,
  1531.                 quantity,
  1532.                 unitPrice,
  1533.                 tax,
  1534.                 discount,
  1535.                 totalPurchasePrice,
  1536.                 warehouseid,
  1537.                 unAllocatedQuantity,
  1538.                 thickness,
  1539.                 width,
  1540.                 height,
  1541.                 cost,
  1542.                 productType,
  1543.                 selectedUnitId = null
  1544.                 ) {
  1545.                 var newQuantity = convertToDecimal(quantity).toNumber();
  1546.                 var newUnAllocatedQuantity = convertToDecimal(unAllocatedQuantity).toNumber();
  1547.                 var newPrice = convertToDecimal(unitPrice).toNumber();
  1548.                 var newTax = convertToDecimal(tax).toNumber();
  1549.                 var newDiscount = convertToDecimal(discount).toNumber();
  1550.                 var newTotalPurchasePrice = convertToDecimal(totalPurchasePrice).toNumber();
  1551.                 if (!issetInSoldList(productid, newQuantity, newPrice, newTax, newDiscount, newTotalPurchasePrice)) {
  1552.                     let productSold = {
  1553.                         uuid: crypto.randomUUID(),
  1554.                         productid: productid,
  1555.                         productName: productName,
  1556.                         code: code,
  1557.                         measurement: measurement,
  1558.                         quantity: newQuantity,
  1559.                         baseUnitQuantity: newQuantity,
  1560.                         unAllocatedQuantity: newUnAllocatedQuantity,
  1561.                         unitPrice: newPrice,
  1562.                         tax: newTax,
  1563.                         discount: newDiscount,
  1564.                         totalPurchasePrice: newTotalPurchasePrice,
  1565.                         warehouse: warehouseid,
  1566.                         thickness: thickness,
  1567.                         width: width,
  1568.                         height: height,
  1569.                         cost: cost,
  1570.                         productType: productType,
  1571.                         selectedUnitId: selectedUnitId,
  1572.                     }
  1573.                     soldList.push(productSold);
  1574.                     // compute base unit quantity asynchronously and update the item
  1575.                     computeBaseUnitQuantity(productid, selectedUnitId, newQuantity, function(baseQty){
  1576.                         const item = soldList.find(i => i.uuid === productSold.uuid);
  1577.                         if(item){ item.baseUnitQuantity = convertToDecimal(baseQty || newQuantity).toNumber(); }
  1578.                     });
  1579.                     fetchStocks();
  1580.                     fetchSoldListRows();
  1581.                     fetchPaymentForm();
  1582.                     \$('#sales_form_totalPurchasePrice').val(addCommas(getTotalSoldAmount()));
  1583.                     return productSold;
  1584.                 } else {
  1585.                     console.log(\"List + \")
  1586.                     console.log(soldList)
  1587.                     throw new Error(\"Ürün zaten listede mevcut !\")
  1588.                 }
  1589.             }
  1590.             // Remove product from sold list by UUID
  1591.             function deleteProductInSoldList(uuid) {
  1592.                 soldList = soldList.filter(product =>
  1593.                     product.uuid !== uuid
  1594.                 );
  1595.                 fetchSoldListRows();
  1596.             }
  1597.             // Mark product as selected and unselect others
  1598.             function selectProduct(productId) {
  1599.                 products.forEach(product => product.selected = false);
  1600.                 let product = products.find(product => product.productid === productId);
  1601.                 if (product) {
  1602.                     product.selected = true;
  1603.                 }
  1604.                 return products;
  1605.             }
  1606.             // Get currently selected product
  1607.             function getSelectedProduct() {
  1608.                 return products.find(product => product.selected === true);
  1609.             }
  1610.             // Update product dropdown with available products
  1611.             function updateProductSelect() {
  1612.                 \$('#productselect').empty();
  1613.                 \$('#productselect').append('<option value=\"0\" data-image=\"image-not-found.webp\">Ürün Seçin</option>');
  1614.                 \$.each(products, function(index, value) {
  1615.                     var image = value.image;
  1616.                     var option = '<option value=\"' + value.id + '\" data-image=\"' + image + '\" class=\"stockoption\">' + value.name + ' - ' + value.code + ' - ' + value.measurement + ' - ' + value.quantity + '</option>';
  1617.                     \$('#productselect').append(option);
  1618.                 });
  1619.                 \$('#productselect').attr('disabled', false);
  1620.             }
  1621.             // Load products from selected warehouse
  1622.             function getProductsFromWarehouse() {
  1623.                 var id = \$('#warehouseselect option:selected').val();
  1624.                 if (!id) {
  1625.                     return;
  1626.                 }
  1627.                 \$.ajax({
  1628.                     url: \"/warehouse-stocks/\" + id,
  1629.                     dataType: 'JSON',
  1630.                     method: 'GET',
  1631.                     success: function(response) {
  1632.                         if (response.length > 0) {
  1633.                             if (soldList.length <= 0) {
  1634.                                 products = [];
  1635.                                 \$.each(response, function(index, product) {
  1636.                                     let productObj = {
  1637.                                         code: product.code,
  1638.                                         id: product.id,
  1639.                                         image: product.image,
  1640.                                         length: 0,
  1641.                                         measurement: product.measurement,
  1642.                                         name: product.name,
  1643.                                         priceFob: 0,
  1644.                                         priceNavlun: 0,
  1645.                                         productid: product.productid,
  1646.                                         purchaseTotalAmount: 0,
  1647.                                         quantity: product.totalQuantity,
  1648.                                         unAllocatedQuantity: 0,
  1649.                                         thickness: 0,
  1650.                                         totalQuantity: product.totalQuantity,
  1651.                                         totalUnitPrice: 0,
  1652.                                         width: 0,
  1653.                                         cost: 0,
  1654.                                         measurementUnit: product.measurementUnit,
  1655.                                         measurementUnitId: product.measurementUnitId,
  1656.                                         stock: 0,
  1657.                                         warehouseid: \$('#warehouseselect option:selected').val(),
  1658.                                         convertibleUnits: [],
  1659.                                         productType: product.productTypeEnum,
  1660.                                     };
  1661.                                     products.push(productObj);
  1662.                                 });
  1663.                                 updateProductSelect();
  1664.                             }
  1665.                         } else {
  1666.                             showErrorAlert('Seçmiş olduğunuz depoda hiç ürün stoğu bulunmamaktadır.');
  1667.                         }
  1668.                     },
  1669.                     error: function(error) {
  1670.                         showErrorAlert('Bilinmeyen bir sistem hatası oluştu lütfen tekrar deneyin.');
  1671.                     }
  1672.                 });
  1673.             }
  1674.             // Update stock quantities based on sold items
  1675.             function fetchStocks() {
  1676.                 // const groupedSoldList = soldList.reduce((acc, soldProduct) => {
  1677.                 //     if (!acc[soldProduct.productid]) {
  1678.                 //         acc[soldProduct.productid] = 0;
  1679.                 //     }
  1680.                 //     acc[soldProduct.productid] += convertToDecimal(soldProduct.quantity).toNumber();
  1681.                 //     return acc;
  1682.                 // }, {});
  1683.                 const groupedSoldList = soldList.reduce((acc, soldProduct) => {
  1684.                     const serviceTypes = [\"INSTALLATION_SERVICE\", \"MAINTENANCE_SERVICE\", \"CONSULTATION_SERVICE\", \"TREE\"];
  1685.                     const productTypeKey = soldProduct.productType ? (soldProduct.productType.key || soldProduct.productType.name) : null;
  1686.                     const isService = productTypeKey ? serviceTypes.includes(productTypeKey) : false;
  1687.                     if (isService) {
  1688.                         return acc;
  1689.                     }
  1690.                     if (!acc[soldProduct.productid]) {
  1691.                         acc[soldProduct.productid] = 0;
  1692.                     }
  1693.                     const quantityToDeduct = soldProduct.baseUnitQuantity || soldProduct.quantity;
  1694.                     acc[soldProduct.productid] += convertToDecimal(quantityToDeduct).toNumber();
  1695.                     return acc;
  1696.                 }, {});
  1697.                 products.forEach(product => {
  1698.                     if (groupedSoldList[product.productid]) {
  1699.                         const totalSoldQuantity = groupedSoldList[product.productid];
  1700.                         product.quantity = roundStockToDecimal(convertToDecimal(product.totalQuantity - totalSoldQuantity).toNumber());
  1701.                     } else {
  1702.                         product.quantity = roundStockToDecimal(convertToDecimal(product.totalQuantity).toNumber());
  1703.                     }
  1704.                 });
  1705.                 calculateAndWriteDiffBetweenPaymentAndSolds();
  1706.             }
  1707.             // Validate stock quantity before adding to sold list
  1708.             // function checkStockQuantity(quantity) {
  1709.             //     let product = products.find(p => p.productid === parseInt(productId, 10));
  1710.             //     const productType = product.productType.key;
  1711.             //     if(productType === \"INSTALLATION_SERVICE\" || productType === \"MAINTENANCE_SERVICE\" || productType === \"CONSULTATION_SERVICE\" || productType === 'TREE'){
  1712.             //
  1713.             //         \$('#updateServiceModal').modal('show');
  1714.             //
  1715.             //     }else{
  1716.             //      if (convertToFloat(quantity) > product.quantity) {
  1717.             //         throw new Error('Yetersiz stok. Ekeleyebileceğiniz maksimum stok: ' + product.quantity);
  1718.             //         resetAddProductForm();
  1719.             //      }
  1720.             //     }
  1721.             //
  1722.             // }
  1723.             function checkStockQuantity() {
  1724.                 return new Promise((resolve, reject) => {
  1725.                     const selectedProduct = getSelectedProduct();
  1726.                     if (!selectedProduct) {
  1727.                         return reject(new Error('Lütfen bir ürün seçin.'));
  1728.                     }
  1729.                     const productType = selectedProduct.productType.key;
  1730.                     const isService = [\"INSTALLATION_SERVICE\", \"MAINTENANCE_SERVICE\", \"CONSULTATION_SERVICE\", \"TREE\"].includes(productType);
  1731.                     if (isService) {
  1732.                         // Eğer ürün bir hizmet ise, stok kontrolü yapma, işlemi onayla.
  1733.                         return resolve();
  1734.                     }
  1735.                     const quantityStr = \$('#adder-allocated-quantity').val();
  1736.                     const fromUnitId = \$('#adder-quantity-unit-select').val();
  1737.                     const requestedQuantity = convertToDecimal(quantityStr).toNumber();
  1738.                     // Eğer birim seçilmemişse veya miktar 0 ise, miktar kadarını stokla karşılaştır.
  1739.                     if (!fromUnitId || fromUnitId === '') {
  1740.                         if (requestedQuantity > selectedProduct.quantity) {
  1741.                             return reject(new Error(`Yetersiz stok. Eklenebilecek maksimum miktar: \${selectedProduct.quantity} \${selectedProduct.measurementUnit}`));
  1742.                         }
  1743.                         return resolve(requestedQuantity); // Temel birimdeki miktarı döndür
  1744.                     }
  1745.                     // Seçilen birimdeki miktarı, ürünün temel birimine çevir.
  1746.                     \$.ajax({
  1747.                         url: '/admin/measurement/convert-to-product-unit',
  1748.                         method: 'POST',
  1749.                         dataType: 'json',
  1750.                         data: {
  1751.                             productId: selectedProduct.productid,
  1752.                             fromUnitId: fromUnitId,
  1753.                             quantity: requestedQuantity
  1754.                         },
  1755.                         success: function(resp) {
  1756.                             if (resp && resp.success) {
  1757.                                 const requestedBaseQuantity = convertToDecimal(resp.result).toNumber();
  1758.                                 // Temel birimdeki talep edilen miktar, stoktan büyük mü diye kontrol et.
  1759.                                 if (requestedBaseQuantity > selectedProduct.quantity) {
  1760.                                     reject(new Error(`Yetersiz stok. Talep edilen miktar (\${quantityStr} \${\$('#adder-quantity-unit-select option:selected').text()}), stoktaki \${selectedProduct.quantity} \${selectedProduct.measurementUnit}'den fazla.`));
  1761.                                 } else {
  1762.                                     resolve(requestedBaseQuantity); // Kontrol başarılı, temel birimdeki miktarı döndür.
  1763.                                 }
  1764.                             } else {
  1765.                                 reject(new Error('Birim dönüştürme sırasında bir hata oluştu. Stok kontrol edilemedi.'));
  1766.                             }
  1767.                         },
  1768.                         error: function() {
  1769.                             reject(new Error('Stok kontrolü sırasında sunucuya ulaşılamadı.'));
  1770.                         }
  1771.                     });
  1772.                 });
  1773.             }
  1774.             // Get product cost information from server
  1775.             function getProductCost(pid) {
  1776.                 const url = '/product-cost/' + pid + '/' + getSelectedProduct().warehouseid;
  1777.                 \$.ajax({
  1778.                     url: \"/product-cost-detail/\" + pid + '?warehouse=' + getSelectedProduct().warehouseid,
  1779.                     method: \"POST\",
  1780.                     dataType: \"JSON\",
  1781.                     success: function(data) {
  1782.                         var product = getSelectedProduct();
  1783.                         product.cost = data.cost;
  1784.                         product.measurementUnit = data.measurement;
  1785.                         \$('.stock-info-span').html(data.stock.toFixed(2).toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, \",\") + \" \" + data.measurement);
  1786.                         \$('.cost-info-span').html(data.cost.toFixed(2).toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, \",\") + \" €\");
  1787.                         \$('.measurement-unit-info-span').html(data.measurement);
  1788.                         \$('#hidden-cost-input').val(data.cost);
  1789.                         const detailsHtml = `
  1790.                             <div class=\"row align-items-center\">
  1791.                                 <div class=\"col-md-3\">\${product.name}</div>
  1792.                                 <div class=\"col-md-3\">
  1793.                                     <strong>
  1794.                                         <button type=\"button\" class=\"btn btn-link btn-sm p-0 cost-popup-btn\" data-url=\"\${url}\">Maliyet: \${data.cost.toFixed(2)} €</button>
  1795.                                     </strong>
  1796.                                 </div>
  1797.                                 <div class=\"col-md-3\"><strong>Stok:</strong> \${data.stock.toFixed(2)} \${data.measurement}</div>
  1798.                                 <div class=\"col-md-3\"><strong>Birim:</strong> \${data.measurement}</div>
  1799.                             </div>
  1800.                         `;
  1801.                         \$('#info-details-content').html(detailsHtml);
  1802.                         return data;
  1803.                     },
  1804.                     error: function(data) {
  1805.                         \$('#info-details-content').html('<div class=\"text-danger\">Ürün maliyet bilgileri yüklenemedi.</div>');
  1806.                     }
  1807.                 });
  1808.             }
  1809.             // Generate HTML for a product row (Standard or AVOIR)
  1810.             function generateProductRowHtml(value, options = {}) {
  1811.                 const isAvoir = options.isAvoir || false;
  1812.                 const readonly = isAvoir ? 'readonly disabled' : '';
  1813.                 const inputReadonly = isAvoir ? 'readonly' : ''; // For inputs we might want just readonly, not disabled
  1814.                 const rowClass = isAvoir ? 'bg-light text-danger' : '';
  1815.                 const uuid = value.uuid;
  1816.                 // Render Service Button (only for standard rows)
  1817.                 const serviceBtnHtml = !isAvoir ? renderServiceEditBtn(value) : '';
  1818.                 
  1819.                 // Actions
  1820.                 let actionButtonsHtml = '';
  1821.                 if (!isAvoir) {
  1822.                     actionButtonsHtml = `
  1823.                         <div class=\"btn-group\" role=\"group\">
  1824.                             \${serviceBtnHtml}
  1825.                             <button type=\"button\" class=\"btn btn-outline-secondary btn-sm open-unallocated-modal-row\"
  1826.                                     data-uuid=\"\${uuid}\" title=\"";
  1827.         // line 1458
  1828.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("unAllocatedQuantity", [], "messages");
  1829.         yield "\">
  1830.                                 <i class=\"fas fa-box-open\"></i>
  1831.                                 <span class=\"badge badge-light ml-1 unalloc-display\">\${value.unAllocatedQuantity.toFixed(2)}</span>
  1832.                             </button>
  1833.                             <button type=\"button\" class=\"btn btn-danger btn-sm delete-row-button\"
  1834.                                     data-uuid=\"\${uuid}\" title=\"Sil\">
  1835.                                 <i class=\"fas fa-trash\"></i>
  1836.                             </button>
  1837.                         </div>
  1838.                     `;
  1839.                 } else {
  1840.                      // Empty for AVOIR
  1841.                      actionButtonsHtml = '';
  1842.                 }
  1843.                 // Info Button
  1844.                 let infoButtonHtml = '';
  1845.                 if (!isAvoir) {
  1846.                      infoButtonHtml = `
  1847.                         <button type=\"button\" class=\"btn btn-sm btn-info btn-icon show-row-info-btn\"
  1848.                                 data-uuid=\"\${uuid}\" title=\"Ürün Bilgileri\">
  1849.                             <i class=\"fas fa-info-circle\"></i>
  1850.                         </button>
  1851.                      `;
  1852.                 }
  1853.                 // Product Select / Name
  1854.                 let productSelectHtml = '';
  1855.                 if (isAvoir) {
  1856.                     // For AVOIR, we just show a static input or disabled select mimicking the look
  1857.                     productSelectHtml = `
  1858.                         <input type=\"text\" class=\"form-control text-danger font-weight-bold\" value=\"AVOIR\" readonly>
  1859.                     `;
  1860.                 } else {
  1861.                      let productOptions = '';
  1862.                      const serviceTypes = ['INSTALLATION_SERVICE','MAINTENANCE_SERVICE','CONSULTATION_SERVICE','TREE'];
  1863.                      const isServiceRow = (function(pt){
  1864.                         try {
  1865.                             if (!pt) return false;
  1866.                             if (typeof pt === 'string') return serviceTypes.includes(pt);
  1867.                             const key = pt.key || pt.name;
  1868.                             return serviceTypes.includes(key);
  1869.                         } catch(e) { return false; }
  1870.                      })(value.productType);
  1871.                      products.forEach(function(product) {
  1872.                         const isSelected = product.productid === value.productid ? 'selected' : '';
  1873.                         const displayName = (isSelected && isServiceRow && value.productName) ? value.productName : product.name;
  1874.                         productOptions += `<option value=\"\${product.productid}\" \${isSelected}>\${displayName} - \${product.measurement} - \${product.quantity} - \${product.code}</option>`;
  1875.                      });
  1876.                      productSelectHtml = `
  1877.                         <select name=\"productId[]\" class=\"form-control product-select-row\" data-uuid=\"\${uuid}\">
  1878.                              \${productOptions}
  1879.                         </select>
  1880.                      `;
  1881.                 }
  1882.                 
  1883.                 // Unallocated Hidden Inputs
  1884.                 const unAllocatedHidens = !isAvoir ? `
  1885.                     <input type=\"hidden\" name=\"warehouseid[]\" value=\"\${value.warehouse}\">
  1886.                     <input type=\"hidden\" name=\"length[]\" value=\"\${value.length || ''}\">
  1887.                     <input type=\"hidden\" name=\"width[]\" value=\"\${value.width || ''}\">
  1888.                     <input type=\"hidden\" name=\"thickness[]\" value=\"\${value.thickness || ''}\">
  1889.                     <input type=\"hidden\" name=\"cost[]\" value=\"\${value.cost || ''}\">
  1890.                     <input type=\"hidden\" name=\"unAllocatedQuantity[]\" class=\"unallocated-quantity-hidden\" value=\"\${value.unAllocatedQuantity}\" data-uuid=\"\${uuid}\">
  1891.                     <input type=\"hidden\" name=\"unAllocatedQuantityUnit[]\" class=\"unallocated-unit-hidden\" value=\"\" data-uuid=\"\${uuid}\">
  1892.                 ` : '';
  1893.                 // Quantity Unit Select
  1894.                 let quantityUnitSelectHtml = '';
  1895.                 if(isAvoir){
  1896.                      quantityUnitSelectHtml = `
  1897.                         <select class=\"custom-select custom-select-sm\" disabled>
  1898.                             <option>-</option>
  1899.                         </select>
  1900.                      `;
  1901.                 } else {
  1902.                     quantityUnitSelectHtml = `
  1903.                         <select class=\"custom-select custom-select-sm quantity-unit-select\"
  1904.                                 name=\"quantityUnit[]\" data-uuid=\"\${uuid}\">
  1905.                             <option value=\"\">-</option>
  1906.                         </select>
  1907.                     `;
  1908.                 }
  1909.                 // Discount Options
  1910.                 let discountOptionsHtml = '';
  1911.                 const discounts = [0, 1, 2, 3, 4, 5, 20, 30, 100];
  1912.                 discounts.forEach(function(d){
  1913.                     discountOptionsHtml += `<option value=\"\${d}\" \${value.discount === d ? 'selected' : ''}>% \${d}</option>`;
  1914.                 });
  1915.                 
  1916.                 // Tax Options
  1917.                 let taxOptionsHtml = '';
  1918.                 const taxes = [0, 10, 20];
  1919.                 taxes.forEach(function(t){
  1920.                     const disabledAttr = t === 0 ? 'disabled' : '';
  1921.                     taxOptionsHtml += `<option value=\"\${t}\" \${value.tax === t ? 'selected' : ''} \${disabledAttr}>% \${t}</option>`;
  1922.                 });
  1923.                 const quantityVal = value.quantity !== undefined ? value.quantity.toFixed(2) : '1.00';
  1924.                 const unitPriceVal = value.unitPrice !== undefined ? value.unitPrice.toFixed(2) : '0.00';
  1925.                 const totalPriceVal = value.totalPurchasePrice !== undefined ? value.totalPurchasePrice.toFixed(2) : '0.00';
  1926.                 // Only standard rows get the name=\"...\" attributes to be submitted
  1927.                 const nameAttr = isAvoir ? '' : 'name=';
  1928.                 return `
  1929.                     <tr id=\"\${uuid}\" data-product-id=\"\${value.productid || ''}\" class=\"\${rowClass}\">
  1930.                         <td>\${infoButtonHtml}</td>
  1931.                         <td class=\"product-select-cell\">
  1932.                             \${productSelectHtml}
  1933.                             \${unAllocatedHidens}
  1934.                         </td>
  1935.                         <td>
  1936.                             <div class=\"input-group input-group-sm\" style=\"max-width: 220px;\">
  1937.                                 <input type=\"number\" \${!isAvoir ? 'name=\"quantity[]\"' : ''}
  1938.                                        class=\"form-control quantity-input-row mask-money \${isAvoir ? 'text-danger' : ''}\"
  1939.                                        value=\"\${quantityVal}\"
  1940.                                        min=\"0\" step=\"0.01\" data-uuid=\"\${uuid}\" \${inputReadonly}>
  1941.                                 <div class=\"input-group-append\">
  1942.                                     \${quantityUnitSelectHtml}
  1943.                                 </div>
  1944.                             </div>
  1945.                         </td>
  1946.                         <td>
  1947.                             <input type=\"text\" \${!isAvoir ? 'name=\"unitPrice[]\"' : ''}
  1948.                                    class=\"form-control form-control-sm price-input-row mask-money \${isAvoir ? 'text-danger' : ''}\"
  1949.                                    value=\"\${unitPriceVal}\"
  1950.                                    min=\"0\" step=\"0.01\" data-uuid=\"\${uuid}\"
  1951.                                    placeholder=\"Birim Fiyat\" \${inputReadonly}>
  1952.                         </td>
  1953.                         <td>
  1954.                             <select \${!isAvoir ? 'name=\"discount[]\"' : ''} class=\"form-control form-control-sm discount-select-row\"
  1955.                                     data-uuid=\"\${uuid}\" \${readonly}>
  1956.                                 \${discountOptionsHtml}
  1957.                             </select>
  1958.                         </td>
  1959.                         <td>
  1960.                             <select \${!isAvoir ? 'name=\"tax[]\"' : ''} class=\"form-control form-control-sm tax-select-row\"
  1961.                                     data-uuid=\"\${uuid}\" \${readonly}>
  1962.                                 \${taxOptionsHtml}
  1963.                             </select>
  1964.                         </td>
  1965.                         <td class=\"text-right\">
  1966.                             <input \${!isAvoir ? 'name=\"totalPrice[]\"' : ''} type=\"text\"
  1967.                                    class=\"form-control form-control-sm total-input-row mask-money \${isAvoir ? 'text-danger font-weight-bold' : ''}\"
  1968.                                    value=\"\${totalPriceVal}\"
  1969.                                    data-uuid=\"\${uuid}\"
  1970.                                    placeholder=\"Toplam\" \${inputReadonly}/>
  1971.                         </td>
  1972.                         <td class=\"text-center\">
  1973.                             \${actionButtonsHtml}
  1974.                         </td>
  1975.                     </tr>
  1976.                     \${!isAvoir ? `
  1977.                     <tr class=\"info-details-row-class\" data-uuid=\"\${uuid}\" style=\"display: none;\">
  1978.                         <td colspan=\"8\" style=\"padding: 0; border-top: none;\">
  1979.                             <div class=\"info-details-content-class p-3\" style=\"display: none;\">
  1980.                                 <div class=\"row\">
  1981.                                     <div class=\"col-md-3\"><strong>Ürün Adı:</strong> \${value.productName}</div>
  1982.                                     <div class=\"col-md-3\"><strong>Kod:</strong> \${value.code}</div>
  1983.                                     <div class=\"col-md-3\"><strong>Ölçü:</strong> \${value.measurement}</div>
  1984.                                     <div class=\"col-md-3\"><strong>Uzunluk:</strong> \${value.length || '-'}</div>
  1985.                                 </div>
  1986.                                 <div class=\"row mt-2\">
  1987.                                     <div class=\"col-md-3\"><strong>Genişlik:</strong> \${value.width || '-'}</div>
  1988.                                     <div class=\"col-md-3\"><strong>Kalınlık:</strong> \${value.thickness || '-'}</div>
  1989.                                     <div class=\"col-md-3\"><strong>Maliyet:</strong> \${(value.cost || 0).toFixed(2)} €</div>
  1990.                                     <div class=\"col-md-3\"><strong>Depo:</strong> \${value.warehouse}</div>
  1991.                                 </div>
  1992.                             </div>
  1993.                         </td>
  1994.                     </tr>` : ''}
  1995.                 `;
  1996.             }
  1997.             // Render sold products table rows with complete editing capabilities
  1998.             // TODO: Seçilen ürün eğer hizmet ise dropdown da hizmet adını kaydedildiği şekilde göster
  1999.             function fetchSoldListRows() {
  2000.                 \$('#product-list-table-tbody').empty();
  2001.                 soldList.forEach(function(value, index) {
  2002.                     const rowHtml = generateProductRowHtml(value, { isAvoir: false });
  2003.                     \$('#product-list-table-tbody').append(rowHtml);
  2004.                     \$(`.product-select-row[data-uuid=\"\${value.uuid}\"]`).select2({
  2005.                         theme: 'bootstrap4',
  2006.                         dropdownCssClass: 'custom-select-dropdown',
  2007.                         placeholder: 'Ürün Seçin',
  2008.                         allowClear: true
  2009.                     });
  2010.                     applyMasks();
  2011.                     // Load measurement units for each product row with default unit
  2012.                     const product = products.find(p => p.productid === value.productid);
  2013.                     const defaultUnitId = product ? product.measurementUnitId : null;
  2014.                     const preferredUnitId = (value.selectedUnitId !== undefined && value.selectedUnitId !== null && value.selectedUnitId !== '') ? value.selectedUnitId : defaultUnitId;
  2015.                     loadMeasurementUnitsForRow(value.productid, value.uuid, preferredUnitId);
  2016.                 });
  2017.                 // Check for Gift Voucher amount and add AVOIR row using reusable component
  2018.                 const totalVoucherAmount = calculateTotalGiftVoucherAmount();
  2019.                 if (!totalVoucherAmount.isZero()) {
  2020.                      const avoirItem = {
  2021.                         uuid: 'avoir-row',
  2022.                         productid: null,
  2023.                         productName: 'AVOIR',
  2024.                         quantity: 1,
  2025.                         unAllocatedQuantity: 0,
  2026.                         unitPrice: totalVoucherAmount.times(-1).toNumber(), // Negative unit price
  2027.                         totalPurchasePrice: totalVoucherAmount.times(-1).toNumber(), // Negative total
  2028.                         discount: 0,
  2029.                         tax: 0
  2030.                      };
  2031.                      
  2032.                      // We override the visual display of the price to be positive in the input if desired, 
  2033.                      // OR we keep it negative to indicate deduction. 
  2034.                      // The user request screenshot showed \"AVOIR\" in red. 
  2035.                      // Standard AVOIR usually implies negative context but let's stick to the styling.
  2036.                      // IMPORTANT: The screenshot usually shows the total as negative, so unit price should likely be negative too.
  2037.                      // Wait, if Quantity is 1 and Total is -Amount, Unit Price must be -Amount.
  2038.                      
  2039.                      const avoirRowHtml = generateProductRowHtml(avoirItem, { isAvoir: true });
  2040.                      \$('#product-list-table-tbody').append(avoirRowHtml);
  2041.                 }
  2042.                 fetchStocks();
  2043.                 updateProductSelect();
  2044.                 updateTotalAmounts();
  2045.                 \$('#warehouseselect').attr('disabled', soldList.length > 0);
  2046.             }
  2047.             // --- GIFT VOUCHER INTEGRATION ---
  2048.             // Set default ID to 0 or a value that won't match if not found.
  2049.             // Using Twig to find the ID.
  2050.             const PAYMENT_METHOD_GIFT_VOUCHER_ID = (function() {
  2051.                 ";
  2052.         // line 1698
  2053.         $context['_parent'] = $context;
  2054.         $context['_seq'] = CoreExtension::ensureTraversable((isset($context["paymentMethods"]) || array_key_exists("paymentMethods"$context) ? $context["paymentMethods"] : (function () { throw new RuntimeError('Variable "paymentMethods" does not exist.'1698$this->source); })()));
  2055.         foreach ($context['_seq'] as $context["_key"] => $context["pm"]) {
  2056.             // line 1699
  2057.             yield "                    ";
  2058.             if (((CoreExtension::getAttribute($this->env$this->source$context["pm"], "name", [], "any"falsefalsefalse1699) == "Hediye Çeki") || (CoreExtension::getAttribute($this->env$this->source$context["pm"], "name", [], "any"falsefalsefalse1699) == "Gift Voucher"))) {
  2059.                 // line 1700
  2060.                 yield "                        return \"";
  2061.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["pm"], "id", [], "any"falsefalsefalse1700), "html"nulltrue);
  2062.                 yield "\";
  2063.                     ";
  2064.             }
  2065.             // line 1702
  2066.             yield "                ";
  2067.         }
  2068.         $_parent $context['_parent'];
  2069.         unset($context['_seq'], $context['_key'], $context['pm'], $context['_parent']);
  2070.         $context array_intersect_key($context$_parent) + $_parent;
  2071.         // line 1703
  2072.         yield "                return null;
  2073.             })();
  2074.             function calculateTotalGiftVoucherAmount() {
  2075.                 let totalVoucher = new Decimal(0);
  2076.                 if (!PAYMENT_METHOD_GIFT_VOUCHER_ID) return totalVoucher;
  2077.                 payments.forEach(function(p) {
  2078.                     if (String(p.paymentMethod) === String(PAYMENT_METHOD_GIFT_VOUCHER_ID)) {
  2079.                         totalVoucher = totalVoucher.plus(convertToDecimal(p.amount));
  2080.                     }
  2081.                 });
  2082.                 return totalVoucher;
  2083.             }
  2084.             // ---------------------------------
  2085.             function renderServiceEditBtn(value){
  2086.               const product = products.find(p => p.productid === value.productid);
  2087.               if (isProductService(product.productid)) {
  2088.                 return `
  2089.                   <button type=\"button\"
  2090.                           class=\"btn btn-warning btn-sm edit-service-button\"
  2091.                           data-uuid=\"\${value.uuid}\"
  2092.                           title=\"Servisi Güncelle\">
  2093.                     <i class=\"fas fa-edit\"></i>
  2094.                   </button>
  2095.                 `;
  2096.               }
  2097.               return ''; // değilse hiç ekleme
  2098.             }
  2099.             function calculateRowFinancials(source) {
  2100.                 const quantity = convertToDecimal(source.quantity || 0);
  2101.                 const unAllocatedQuantity = convertToDecimal(source.unAllocatedQuantity || 0);
  2102.                 const unitPrice = convertToDecimal(source.unitPrice || 0);
  2103.                 const discountPercentage = convertToDecimal(source.discount || 0);
  2104.                 const taxPercentage = convertToDecimal(source.tax || 0);
  2105.                 const totalQuantity = quantity.plus(unAllocatedQuantity);
  2106.                 if (totalQuantity.isZero()) {
  2107.                     return {
  2108.                         subtotal: new Decimal(0),
  2109.                         discountAmount: new Decimal(0),
  2110.                         afterDiscount: new Decimal(0),
  2111.                         taxAmount: new Decimal(0),
  2112.                         total: new Decimal(0),
  2113.                         totalRounded: new Decimal(0),
  2114.                         taxPercentage
  2115.                     };
  2116.                 }
  2117.                 const subtotal = totalQuantity.mul(unitPrice);
  2118.                 const discountAmount = subtotal.mul(discountPercentage.div(100));
  2119.                 const afterDiscount = subtotal.minus(discountAmount);
  2120.                 const taxAmount = afterDiscount.mul(taxPercentage.div(100));
  2121.                 const total = afterDiscount.plus(taxAmount);
  2122.                 return {
  2123.                     subtotal,
  2124.                     discountAmount,
  2125.                     afterDiscount,
  2126.                     taxAmount,
  2127.                     total,
  2128.                     totalRounded: total.toDecimalPlaces(2, MONEY_ROUNDING_MODE),
  2129.                     taxPercentage
  2130.                 };
  2131.             }
  2132.             function aggregateSoldTotals() {
  2133.                 const aggregation = {
  2134.                     grossTotal: new Decimal(0),
  2135.                     totalDiscount: new Decimal(0),
  2136.                     subtotal: new Decimal(0),
  2137.                     tax: new Decimal(0),
  2138.                     grandTotal: new Decimal(0),
  2139.                     byTaxRate: {}
  2140.                 };
  2141.                 soldList.forEach(function(item) {
  2142.                     // item.totalPurchasePrice'ı kullan (manuel veya otomatik hesaplanmış)
  2143.                     const itemTotal = convertToDecimal(item.totalPurchasePrice || 0);
  2144.                     // Toplam üzerinden geriye doğru hesaplama
  2145.                     // Formül: total = subtotal × (1 - discount%) × (1 + tax%)
  2146.                     // Ters formül: afterDiscount = total / (1 + tax%)
  2147.                     //              subtotal = afterDiscount / (1 - discount%)
  2148.                     const taxPercentage = convertToDecimal(item.tax || 0);
  2149.                     const discountPercentage = convertToDecimal(item.discount || 0);
  2150.                     const taxMultiplier = new Decimal(1).plus(taxPercentage.div(100));
  2151.                     // Adım 1: KDV'yi çıkar → İndirim sonrası tutarı bul
  2152.                     // afterDiscount = total / (1 + tax%)
  2153.                     const afterDiscount = itemTotal.div(taxMultiplier);
  2154.                     // Adım 2: KDV tutarını hesapla
  2155.                     // taxAmount = afterDiscount × tax%
  2156.                     const taxAmount = afterDiscount.mul(taxPercentage.div(100));
  2157.                     // NOT: \"Ara Toplam\" (subtotal) = afterDiscount (indirim uygulanmış tutar)
  2158.                     // Çünkü görüntülenen \"Ara Toplam\" indirim sonrası, KDV öncesi tutar
  2159.                     // Calculate Gross (before discount)
  2160.                     const quantity = convertToDecimal(item.quantity).plus(convertToDecimal(item.unAllocatedQuantity));
  2161.                     const unitPrice = convertToDecimal(item.unitPrice); 
  2162.                     const grossLine = quantity.mul(unitPrice);
  2163.                     
  2164.                     // Calculate Discount derived from Gross vs Net
  2165.                     const discountAmount = grossLine.minus(afterDiscount);
  2166.                     aggregation.grossTotal = aggregation.grossTotal.plus(grossLine);
  2167.                     aggregation.totalDiscount = aggregation.totalDiscount.plus(discountAmount);
  2168.                     aggregation.subtotal = aggregation.subtotal.plus(afterDiscount);
  2169.                     aggregation.tax = aggregation.tax.plus(taxAmount);
  2170.                     aggregation.grandTotal = aggregation.grandTotal.plus(itemTotal);
  2171.                     const rateKey = taxPercentage.toFixed(4);
  2172.                     if (!aggregation.byTaxRate[rateKey]) {
  2173.                         aggregation.byTaxRate[rateKey] = {
  2174.                             rate: taxPercentage,
  2175.                             amount: new Decimal(0)
  2176.                         };
  2177.                     }
  2178.                     aggregation.byTaxRate[rateKey].amount = aggregation.byTaxRate[rateKey].amount.plus(taxAmount);
  2179.                 });
  2180.                 aggregation.subtotalRounded = aggregation.subtotal.toDecimalPlaces(2, MONEY_ROUNDING_MODE);
  2181.                 aggregation.taxRounded = aggregation.tax.toDecimalPlaces(2, MONEY_ROUNDING_MODE);
  2182.                 aggregation.grandTotalRounded = aggregation.grandTotal.toDecimalPlaces(2, MONEY_ROUNDING_MODE);
  2183.                 return aggregation;
  2184.             }
  2185.             // Track which row is being updated to prevent circular updates
  2186.             let rowUpdatingFromTotal = {};
  2187.             let rowUpdatingFromUnitPrice = {};
  2188.             // Track rows where total was manually entered (should not recalculate total)
  2189.             let rowHasManualTotal = {};
  2190.             function updateSoldProductFromRow(uuid) {
  2191.                 const itemIndex = soldList.findIndex(item => item.uuid === uuid);
  2192.                 if (itemIndex === -1) {
  2193.                     return;
  2194.                 }
  2195.                 // Eğer bu satır toplam tarafından güncelleniyorsa, tekrar toplam güncelleme
  2196.                 if(rowUpdatingFromTotal[uuid]) {
  2197.                     return;
  2198.                 }
  2199.                 rowUpdatingFromUnitPrice[uuid] = true;
  2200.                 const \$row = \$(`#\${uuid}`);
  2201.                 const quantity = convertToDecimal(\$row.find('.quantity-input-row').val()).toNumber();
  2202.                 const unitPrice = convertToDecimal(\$row.find('.price-input-row').val()).toNumber();
  2203.                 const discount = convertToDecimal(\$row.find('.discount-select-row').val()).toNumber();
  2204.                 const tax = convertToDecimal(\$row.find('.tax-select-row').val()).toNumber();
  2205.                 soldList[itemIndex].quantity = quantity;
  2206.                 soldList[itemIndex].unitPrice = unitPrice;
  2207.                 soldList[itemIndex].discount = discount;
  2208.                 soldList[itemIndex].tax = tax;
  2209.                 const selectedUnitId = \$row.find('.quantity-unit-select').val();
  2210.                 computeBaseUnitQuantity(soldList[itemIndex].productid, selectedUnitId, quantity, function(baseQty){
  2211.                     soldList[itemIndex].baseUnitQuantity = convertToDecimal(baseQty || quantity).toNumber();
  2212.                 });
  2213.                 // Eğer bu satırda manuel toplam girildiyse, toplam sabit kalmalı, sadece birim fiyat güncellensin
  2214.                 if (rowHasManualTotal[uuid]) {
  2215.                     // Manuel toplam korunuyor, birim fiyatı tersine hesapla
  2216.                     const manualTotal = convertToDecimal(soldList[itemIndex].totalPurchasePrice);
  2217.                     const totalQuantity = convertToDecimal(quantity).plus(convertToDecimal(soldList[itemIndex].unAllocatedQuantity || 0));
  2218.                     if (!totalQuantity.isZero()) {
  2219.                         const discountMultiplier = new Decimal(1).minus(convertToDecimal(discount).div(100));
  2220.                         const taxMultiplier = new Decimal(1).plus(convertToDecimal(tax).div(100));
  2221.                         if (discountMultiplier.isZero()) {
  2222.                             soldList[itemIndex].unitPrice = 0;
  2223.                             \$row.find('.price-input-row').val('0.00');
  2224.                         } else if (!taxMultiplier.isZero()) {
  2225.                             const calculatedUnitPrice = manualTotal
  2226.                                 .div(taxMultiplier)
  2227.                                 .div(discountMultiplier)
  2228.                                 .div(totalQuantity)
  2229.                                 .toDecimalPlaces(6, MONEY_ROUNDING_MODE);
  2230.                             soldList[itemIndex].unitPrice = calculatedUnitPrice.toNumber();
  2231.                             \$row.find('.price-input-row').val(calculatedUnitPrice.toDecimalPlaces(2, MONEY_ROUNDING_MODE).toFixed(2));
  2232.                         }
  2233.                     }
  2234.                     // Toplam input'u DEĞİŞTİRME - manuel değer korunuyor
  2235.                 } else {
  2236.                     // Normal hesaplama - toplam otomatik hesaplansın
  2237.                     const rowTotals = calculateRowFinancials(soldList[itemIndex]);
  2238.                     soldList[itemIndex].totalPurchasePrice = rowTotals.totalRounded.toNumber();
  2239.                     \$row.find('.total-input-row').val(rowTotals.totalRounded.toFixed(2));
  2240.                 }
  2241.                 updateTotalAmounts();
  2242.                 fetchStocks();
  2243.                 fetchPaymentForm();
  2244.                 setTimeout(function(){ delete rowUpdatingFromUnitPrice[uuid]; }, 0);
  2245.             }
  2246.             // Toplam tutar değiştirildiğinde birim fiyatı tersine hesaplar
  2247.             function updateUnitPriceFromTotal(uuid) {
  2248.                 const itemIndex = soldList.findIndex(item => item.uuid === uuid);
  2249.                 if (itemIndex === -1) {
  2250.                     return;
  2251.                 }
  2252.                 // Eğer bu satır birim fiyat tarafından güncelleniyorsa, döngüyü engelle
  2253.                 if(rowUpdatingFromUnitPrice[uuid]) {
  2254.                     return;
  2255.                 }
  2256.                 rowUpdatingFromTotal[uuid] = true;
  2257.                 // ÖNEMLİ: Toplam manuel girildi, bu satırı işaretle
  2258.                 rowHasManualTotal[uuid] = true;
  2259.                 const \$row = \$(`#\${uuid}`);
  2260.                 const totalValue = convertToDecimal(\$row.find('.total-input-row').val());
  2261.                 const item = soldList[itemIndex];
  2262.                 const totalQuantity = convertToDecimal(item.quantity || 0).plus(convertToDecimal(item.unAllocatedQuantity || 0));
  2263.                 if (totalQuantity.isZero()) {
  2264.                     setTimeout(function(){ delete rowUpdatingFromTotal[uuid]; }, 0);
  2265.                     return;
  2266.                 }
  2267.                 // Manuel girilen toplam değerini kaydet
  2268.                 soldList[itemIndex].totalPurchasePrice = totalValue.toNumber();
  2269.                 // Eğer toplam 0 ise, birim fiyat da 0 olmalı
  2270.                 if (totalValue.isZero()) {
  2271.                     \$row.find('.price-input-row').val('0.00');
  2272.                     soldList[itemIndex].unitPrice = 0;
  2273.                     updateTotalAmounts();
  2274.                     fetchStocks();
  2275.                     fetchPaymentForm();
  2276.                     setTimeout(function(){ delete rowUpdatingFromTotal[uuid]; }, 0);
  2277.                     return;
  2278.                 }
  2279.                 const discountMultiplier = new Decimal(1).minus(convertToDecimal(item.discount || 0).div(100));
  2280.                 const taxMultiplier = new Decimal(1).plus(convertToDecimal(item.tax || 0).div(100));
  2281.                 // %100 indirimde discountMultiplier = 0 olur, bu durumda birim fiyat 0 olmalı
  2282.                 if (discountMultiplier.isZero()) {
  2283.                     \$row.find('.price-input-row').val('0.00');
  2284.                     soldList[itemIndex].unitPrice = 0;
  2285.                     updateTotalAmounts();
  2286.                     fetchStocks();
  2287.                     fetchPaymentForm();
  2288.                     setTimeout(function(){ delete rowUpdatingFromTotal[uuid]; }, 0);
  2289.                     return;
  2290.                 }
  2291.                 if (taxMultiplier.isZero()) {
  2292.                     setTimeout(function(){ delete rowUpdatingFromTotal[uuid]; }, 0);
  2293.                     return;
  2294.                 }
  2295.                 // Formül: unitPrice = total / ((1 + tax%) * (1 - discount%) * quantity)
  2296.                 const unitPrice = totalValue
  2297.                     .div(taxMultiplier)
  2298.                     .div(discountMultiplier)
  2299.                     .div(totalQuantity)
  2300.                     .toDecimalPlaces(6, MONEY_ROUNDING_MODE);
  2301.                 \$row.find('.price-input-row').val(unitPrice.toDecimalPlaces(2, MONEY_ROUNDING_MODE).toFixed(2));
  2302.                 soldList[itemIndex].unitPrice = unitPrice.toNumber();
  2303.                 // Sadece stok ve genel toplamları güncelle, satır toplamını değiştirme
  2304.                 updateTotalAmounts();
  2305.                 fetchStocks();
  2306.                 fetchPaymentForm();
  2307.                 setTimeout(function(){ delete rowUpdatingFromTotal[uuid]; }, 0);
  2308.             }
  2309.             // =============================================================================
  2310.             // WAREHOUSE SELECTION EVENT HANDLER
  2311.             // =============================================================================
  2312.             // Handle warehouse selection change
  2313.             \$('#warehouseselect').on('change', function() {
  2314.                 getProductsFromWarehouse();
  2315.             });
  2316.             // Auto-select warehouse if there is only one
  2317.             var \$warehouseSelect = \$('#warehouseselect');
  2318.             if (\$warehouseSelect.find('option').length === 2 && \$warehouseSelect.val() === \"\") {
  2319.                  var firstWarehouseVal = \$warehouseSelect.find('option').eq(1).val();
  2320.                  \$warehouseSelect.val(firstWarehouseVal).trigger('change');
  2321.             }
  2322.             // Load measurement units for a specific product row (with caching)
  2323.             let measurementUnitsCache = {};
  2324.             function loadMeasurementUnitsForRow(productId, uuid, defaultUnitId = null) {
  2325.                 // Check cache first
  2326.                 if (measurementUnitsCache[productId]) {
  2327.                     populateUnitSelectForRow(uuid, measurementUnitsCache[productId], defaultUnitId);
  2328.                     return;
  2329.                 }
  2330.                 // Load from server if not cached
  2331.                 \$.get('/product/' + productId + '/measurement-units', function(units) {
  2332.                     // Cache the units
  2333.                     measurementUnitsCache[productId] = units || [];
  2334.                     populateUnitSelectForRow(uuid, units, defaultUnitId);
  2335.                 }).fail(function() {
  2336.                     console.log('Failed to load measurement units for product:', productId);
  2337.                     measurementUnitsCache[productId] = []; // Cache empty array to prevent repeated requests
  2338.                 });
  2339.             }
  2340.             // Populate unit select dropdown for a specific row
  2341.             function populateUnitSelectForRow(uuid, units, defaultUnitId = null) {
  2342.                 const \$select = \$(`.quantity-unit-select[data-uuid=\"\${uuid}\"]`);
  2343.                 \$select.empty();
  2344.                 if (Array.isArray(units) && units.length > 0) {
  2345.                     units.forEach(function(unit) {
  2346.                         const isSelected = defaultUnitId !== null && defaultUnitId !== undefined && defaultUnitId !== '' && String(unit.id) === String(defaultUnitId);
  2347.                         const selectedAttr = isSelected ? ' selected' : '';
  2348.                         \$select.append('<option value=\"' + unit.id + '\"' + selectedAttr + '>' + unit.symbol + '</option>');
  2349.                     });
  2350.                     if (units.length === 1) {
  2351.                         \$select.prop('disabled', true);
  2352.                     } else {
  2353.                         \$select.prop('disabled', false);
  2354.                     }
  2355.                 } else {
  2356.                     \$select.append('<option value=\"\">-</option>');
  2357.                     \$select.prop('disabled', false);
  2358.                 }
  2359.             }
  2360.             // Update total amounts in footer
  2361.             function updateTotalAmounts() {
  2362.                 const taxLabelPrefix = \"TVA\";
  2363.                 const taxTotalLabel = \"";
  2364.         // line 2058
  2365.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("total"), "js"), "html"nulltrue);
  2366.         yield "\";
  2367.                 const formatTaxRate = function(rateDecimal) {
  2368.                     const rateNumber = convertToDecimal(rateDecimal || 0).toNumber();
  2369.                     if (!isFinite(rateNumber)) {
  2370.                         return \"0\";
  2371.                     }
  2372.                     if (Math.abs(rateNumber % 1) < 1e-6) {
  2373.                         return rateNumber.toFixed(0);
  2374.                     }
  2375.                     return rateNumber.toFixed(2).replace(/\\.?0+\$/, \"\");
  2376.                 };
  2377.                 const totals = aggregateSoldTotals();
  2378.                 const \$tfoot = \$(\"#product-list-table tfoot\");
  2379.                 \$tfoot.empty();
  2380.                 // Helper to create row
  2381.                 const addRow = (label, value, isBold=false, colorClass='') => {
  2382.                     const row = \$(`<tr class=\"summary-row \${isBold ? 'font-weight-bold' : ''} \${colorClass}\">
  2383.                         <td colspan=\"8\">
  2384.                             <div class=\"sale-summary-row\">
  2385.                                 <span class=\"summary-label\">\${label}</span>
  2386.                                 <span class=\"summary-value\">\${formatCurrency(value)}</span>
  2387.                             </div>
  2388.                         </td>
  2389.                     </tr>`);
  2390.                     \$tfoot.append(row);
  2391.                 };
  2392.                 // 1. Total H.T. (Gross)
  2393.                 addRow('Total H.T.:', totals.grossTotal, true);
  2394.                 // 2. Remise
  2395.                 if (!totals.totalDiscount.isZero() && totals.totalDiscount.toNumber() > 0.005) {
  2396.                      const \$row = \$(`<tr class=\"summary-row\">
  2397.                         <td colspan=\"8\">
  2398.                             <div class=\"sale-summary-row\">
  2399.                                 <span class=\"summary-label\">Remise:</span>
  2400.                                 <span class=\"summary-value\">\${formatCurrency(totals.totalDiscount.negated())}</span>
  2401.                             </div>
  2402.                         </td>
  2403.                     </tr>`);
  2404.                     \$tfoot.append(\$row);
  2405.                 }
  2406.                 // 3. Total H.T. (Net)
  2407.                 addRow('Total H.T.:', totals.subtotal, true);
  2408.                 // 4. AVOIR
  2409.                 const totalVoucherAmount = calculateTotalGiftVoucherAmount();
  2410.                 let finalTotal = totals.grandTotalRounded; // Assuming totals.grandTotalRounded is available in result? Yes
  2411.                 // Wait, aggregateSoldTotals returns grandTotalRounded.
  2412.                 // But calculateSaleSummary in edit.html.twig returned summary.roundedTotal.
  2413.                 
  2414.                 if (!totalVoucherAmount.isZero()) {
  2415.                     const \$avoirRow = \$(`<tr class=\"summary-row text-danger font-weight-bold\">
  2416.                         <td colspan=\"8\">
  2417.                             <div class=\"sale-summary-row\">
  2418.                                 <span class=\"summary-label\">AVOIR:</span>
  2419.                                 <span class=\"summary-value\">-\${formatCurrency(totalVoucherAmount)}</span>
  2420.                             </div>
  2421.                         </td>
  2422.                     </tr>`);
  2423.                     \$tfoot.append(\$avoirRow);
  2424.                     
  2425.                     finalTotal = finalTotal.minus(totalVoucherAmount);
  2426.                 }
  2427.                 // 5. TVA
  2428.                 const taxEntries = Object.values(totals.byTaxRate)
  2429.                     .filter(function(entry) { return !entry.amount.isZero(); })
  2430.                     .sort(function(a, b) { return a.rate.toNumber() - b.rate.toNumber(); });
  2431.                 if (taxEntries.length) {
  2432.                     taxEntries.forEach(function(entry) {
  2433.                          addRow(taxLabelPrefix + \" (\" + formatTaxRate(entry.rate) + \"%):\", entry.amount);
  2434.                     });
  2435.                 } else {
  2436.                      addRow(taxLabelPrefix + \" (0%):\", 0);
  2437.                 }
  2438.                 // 6. TOTAL
  2439.                 const \$totalRow = \$(`<tr class=\"total-row summary-row font-weight-bold\">
  2440.                     <td colspan=\"8\">
  2441.                         <div class=\"sale-summary-row summary-total\">
  2442.                             <span class=\"summary-label\">TOTAL À PAYER (EUR):</span>
  2443.                             <span class=\"summary-value display-5\">\${formatCurrency(finalTotal)}</span>
  2444.                         </div>
  2445.                     </td>
  2446.                 </tr>`);
  2447.                 \$tfoot.append(\$totalRow);
  2448.                 calculateAndWriteDiffBetweenPaymentAndSolds();
  2449.             }
  2450.             // Update sold list item by UUID
  2451.             function updateSoldListItem(uuid, field, value) {
  2452.                 const itemIndex = soldList.findIndex(item => item.uuid === uuid);
  2453.                 if (itemIndex === -1) {
  2454.                     return;
  2455.                 }
  2456.                 soldList[itemIndex][field] = convertToDecimal(value).toNumber();
  2457.                 updateSoldProductFromRow(uuid);
  2458.             }
  2459.             // Satıştaki miktarları listeden düşme Un Allocated HARİÇ tutulur
  2460.             function fetchStocks() {
  2461.                 // soldList'i productid'e göre grupla
  2462.                 const groupedSoldList = soldList.reduce((acc, soldProduct) => {
  2463.                     if (!acc[soldProduct.productid]) {
  2464.                         acc[soldProduct.productid] = 0;
  2465.                     }
  2466.                     acc[soldProduct.productid] += convertToDecimal(soldProduct.baseUnitQuantity).toNumber();
  2467.                     return acc;
  2468.                 }, {});
  2469.                 // products listesindeki totalQuantity'yi güncelle
  2470.                 products.forEach(product => {
  2471.                     if (groupedSoldList[product.productid]) {
  2472.                         const totalSoldQuantity = groupedSoldList[product.productid];
  2473.                         product.quantity = roundStockToDecimal(convertToDecimal(product.totalQuantity - totalSoldQuantity).toNumber());
  2474.                     } else {
  2475.                         // Eğer soldList'te bu ürün yoksa, quantity aynı kalır
  2476.                         product.quantity = roundStockToDecimal(convertToDecimal(product.totalQuantity).toNumber());
  2477.                     }
  2478.                 });
  2479.                 calculateAndWriteDiffBetweenPaymentAndSolds();
  2480.             }
  2481.             function getTotalSoldAmount() {
  2482.                 return aggregateSoldTotals().grandTotalRounded.toNumber();
  2483.             }
  2484.             \$(document).on('blur', '#payment-list-table-tbody .payment-amount-input', function() {
  2485.                 // Buraya kod eklenebilir
  2486.             });
  2487.             // Gelen değeri decimale çevirme
  2488.             function convertToDecimal(value) {
  2489.                 try {
  2490.                     if (value instanceof Decimal) {
  2491.                         return value;
  2492.                     }
  2493.                     if (value === undefined || value === null) {
  2494.                         return new Decimal(0);
  2495.                     }
  2496.                     if (typeof value === 'number') {
  2497.                         if (!isFinite(value) || isNaN(value)) {
  2498.                             return new Decimal(0);
  2499.                         }
  2500.                         return new Decimal(value);
  2501.                     }
  2502.                     if (typeof value === 'string') {
  2503.                         // Keep digits, minus, dot and comma; strip others
  2504.                         var sanitized = value.replace(/[^0-9.,-]/g, '').replace(/,/g, '').trim();
  2505.                         if (sanitized === '' || sanitized === '-' || sanitized === '.' || sanitized === '-.') {
  2506.                             return new Decimal(0);
  2507.                         }
  2508.                         return new Decimal(sanitized);
  2509.                     }
  2510.                     return new Decimal(0);
  2511.                 } catch (e) {
  2512.                     return new Decimal(0);
  2513.                 }
  2514.             }
  2515.             // Seçilen ürünün birimini dropdown'da gösterme (handled by main product select handler)
  2516.             function clearUnitSelects(){
  2517.                 \$('#adder-quantity-unit-select').empty().append('<option value=\"\">-</option>');
  2518.                 \$('#adder-unallocated-quantity-unit-select').empty().append('<option value=\"\">-</option>');
  2519.                 \$('#modal-unallocated-unit').empty().append('<option value=\"\">-</option>');
  2520.             }
  2521.             // Select içine çevrilebilir birimleri koyuyor
  2522.             function populateSelectWithUnits(\$select, units) {
  2523.                 \$select.empty();
  2524.                 if (Array.isArray(units) && units.length > 0) {
  2525.                     units.forEach(function(unit) {
  2526.                         \$select.append('<option value=\"' + unit.id + '\">' + unit.symbol + '</option>');
  2527.                     });
  2528.                     if (units.length === 1) {
  2529.                         \$select.prop('disabled', true);
  2530.                     } else {
  2531.                         \$select.prop('disabled', false);
  2532.                     }
  2533.                 } else {
  2534.                     \$select.append('<option value=\"\">-</option>');
  2535.                     \$select.prop('disabled', false);
  2536.                 }
  2537.             }
  2538.             // Ürünün çevrilebilir birimlerini select içine koyuyoruz.
  2539.             function refreshUnitSelectsForProduct(product) {
  2540.                 if (!product || !product.convertibleUnits) {
  2541.                     clearUnitSelects();
  2542.                     return;
  2543.                 }
  2544.                 populateSelectWithUnits(\$('#adder-quantity-unit-select'), product.convertibleUnits);
  2545.                 populateSelectWithUnits(\$('#adder-unallocated-quantity-unit-select'), product.convertibleUnits);
  2546.                 populateSelectWithUnits(\$('#modal-unallocated-unit'), product.convertibleUnits);
  2547.             }
  2548.             // TODO:  Birimler doldurulurken ilgili birimin karşılığındaki miktar yazılacak
  2549.             function fillUnitSelects(product){
  2550.                 // Check cache first
  2551.                 if (measurementUnitsCache[product.productid]) {
  2552.                     product.convertibleUnits = measurementUnitsCache[product.productid];
  2553.                     refreshUnitSelectsForProduct(product);
  2554.                     computeAndShowBaseUnitEquivalent();
  2555.                     return;
  2556.                 }
  2557.                 \$.get('/product/' + product.productid + '/measurement-units', function(units) {
  2558.                     // Cache the units
  2559.                     measurementUnitsCache[product.productid] = units || [];
  2560.                     // Store in product object
  2561.                     product.convertibleUnits = units || [];
  2562.                     // Update selects
  2563.                     refreshUnitSelectsForProduct(product);
  2564.                     // Set default unit as selected
  2565.                     if (product.measurementUnitId) {
  2566.                         \$('#adder-quantity-unit-select').val(product.measurementUnitId);
  2567.                         \$('#adder-unallocated-quantity-unit-select').val(product.measurementUnitId);
  2568.                         \$('#modal-unallocated-unit').val(product.measurementUnitId);
  2569.                     }
  2570.                     computeAndShowBaseUnitEquivalent();
  2571.                 });
  2572.             }
  2573.             // Seçilen birimde girilen miktarın, ürünün KENDİ birimindeki karşılığını hesaplar ve inputun altına küçük yazıyla gösterir
  2574.             function computeAndShowBaseUnitEquivalent() {
  2575.                 try {
  2576.                     const selectedProduct = getSelectedProduct();
  2577.                     if (!selectedProduct || !selectedProduct.productid) {
  2578.                         updateAllocatedQuantityHint('');
  2579.                         return;
  2580.                     }
  2581.                     const fromUnitId = \$('#adder-quantity-unit-select').val();
  2582.                     const qtyStr = \$('#adder-allocated-quantity').val();
  2583.                     // If base unit is selected, do not show duplicate label
  2584.                     if (fromUnitId && String(fromUnitId) === String(selectedProduct.measurementUnitId)) {
  2585.                         updateAllocatedQuantityHint('');
  2586.                         return;
  2587.                     }
  2588.                     if (!fromUnitId || fromUnitId === '' || qtyStr === '' || qtyStr === null) {
  2589.                         updateAllocatedQuantityHint('');
  2590.                         return;
  2591.                     }
  2592.                     const quantity = convertToDecimal(qtyStr).toNumber();
  2593.                     if (isNaN(quantity)) {
  2594.                         updateAllocatedQuantityHint('');
  2595.                         return;
  2596.                     }
  2597.                     \$.ajax({
  2598.                         url: '/admin/measurement/convert-to-product-unit',
  2599.                         method: 'POST',
  2600.                         dataType: 'json',
  2601.                         data: {
  2602.                             productId: selectedProduct.productid,
  2603.                             fromUnitId: fromUnitId,
  2604.                             quantity: quantity
  2605.                         },
  2606.                         success: function(resp) {
  2607.                             if (resp && resp.success) {
  2608.                                 const unitText = selectedProduct.measurementUnit ? (' ' + selectedProduct.measurementUnit) : '';
  2609.                                 updateAllocatedQuantityHint((Number(resp.result).toFixed(2)) + unitText);
  2610.                             } else {
  2611.                                 updateAllocatedQuantityHint('');
  2612.                             }
  2613.                         },
  2614.                         error: function() {
  2615.                             updateAllocatedQuantityHint('');
  2616.                         }
  2617.                     });
  2618.                 } catch (e) {
  2619.                     updateAllocatedQuantityHint('');
  2620.                 }
  2621.             }
  2622.             // Base unit tipinden miktar.
  2623.             function updateAllocatedQuantityHint(text) {
  2624.                 const \$group = \$('#adder-allocated-quantity').closest('.input-group');
  2625.                 if (\$('#allocated-quantity-converted-hint').length === 0) {
  2626.                     \$('<small id=\"allocated-quantity-converted-hint\" class=\"form-text text-muted\"></small>').insertAfter('#adder-quantity-unit-select');
  2627.                 }
  2628.                 \$('#allocated-quantity-converted-hint').text(text || '');
  2629.             }
  2630.             function roundToDecimal(value, decimalPlaces = 2) {
  2631.                 const decimalValue = new Decimal(value);
  2632.                 const roundedValue = decimalValue.toDecimalPlaces(decimalPlaces, Decimal.ROUND_UP);
  2633.                 return roundedValue.toNumber();
  2634.             }
  2635.             function roundStockToDecimal(value, decimalPlaces = 2) {
  2636.                 const decimalValue = new Decimal(value);
  2637.                 const roundedValue = decimalValue.toDecimalPlaces(decimalPlaces, Decimal.ROUND_DOWN);
  2638.                 return roundedValue.toNumber();
  2639.             }
  2640.             function selectProduct(productId) {
  2641.                 products.forEach(product => product.selected = false);
  2642.                 let product = products.find(product => product.productid === productId);
  2643.                 if (product) {
  2644.                     product.selected = true;
  2645.                 }
  2646.                 return products;
  2647.             }
  2648.             function getSelectedProduct() {
  2649.                 return products.find(product => product.selected === true);
  2650.             }
  2651.             // Ürün seçme selectini yeniden güncelleme.
  2652.             function updateProductSelect() {
  2653.                 \$('#productselect').empty();
  2654.                 \$('#productselect').append('<option value=\"0\" data-image=\"image-not-found.webp\">Ürün Seçin</option>');
  2655.                 \$.each(products, function(index, value) {
  2656.                     var image = value.image;
  2657.                     var option = '<option value=\"' + value.id + '\" data-image=\"' + image + '\" class=\"stockoption\">' + value.name + ' - ' + value.code + ' - ' + value.measurement + ' - ' + value.quantity + '</option>';
  2658.                     \$('#productselect').append(option);
  2659.                 });
  2660.                 \$('#productselect').attr('disabled', false);
  2661.             }
  2662.             \$('#products_sold_quantity').mask(\"##0.00\", {
  2663.                 reverse: true
  2664.             });
  2665.             \$('#adder-allocated-quantity').mask(\"##0.00\", {
  2666.                 reverse: true
  2667.             });
  2668.             \$('#adder-unallocated-quantity').mask(\"##0.00\", {
  2669.                 reverse: true
  2670.             });
  2671.             \$('#adder-price').mask(\"##0.00\", {
  2672.                 reverse: true
  2673.             });
  2674.             \$('#adder-total').mask(\"##0.00\", {
  2675.                 reverse: true
  2676.             });
  2677.             \$('#products_sold_unitPriceFob').mask(\"#,##0.00\", {
  2678.                 reverse: true
  2679.             });
  2680.             \$('#products_sold_unitPriceNavlun').mask(\"#,##0.00\", {
  2681.                 reverse: true
  2682.             });
  2683.             \$('#products_sold_totalUnitPrice').mask(\"#,##0.00\", {
  2684.                 reverse: true
  2685.             });
  2686.             \$('#products_sold_totalUnitPurchasePrice').mask(\"#,##0.00\", {
  2687.                 reverse: true
  2688.             });
  2689.             \$('#products_sold_totalPrice').mask(\"#,##0.00\", {
  2690.                 reverse: true
  2691.             });
  2692.             \$('#products_sold_totalPuchasePrice').mask(\"#,##0.00\", {
  2693.                 reverse: true
  2694.             });
  2695.             \$('#sales_form_totalPurchasePrice').mask(\"#,##0.00\", {
  2696.                 reverse: true
  2697.             });
  2698.             \$('#sales_form_totalPurchasePrice').attr('readonly', 'readonly');
  2699.             var totalQuantity = 0;
  2700.             var productId = 0;
  2701.             var productname = \$('#products_sold_productName');
  2702.             var productmeasurement = \$('#products_sold_measurement');
  2703.             var unitPriceFob = \$('#products_sold_unitPriceFob');
  2704.             var unitPricenavlun = \$('#products_sold_unitPriceNavlun');
  2705.             var totalUnitPrice = \$('#products_sold_totalUnitPrice');
  2706.             // ÖDEME FORMU LİSTEYE EKLEME
  2707.             \$('#save-payment-btn').on('click', function() {
  2708.                 let amount = roundToDecimal(convertToDecimal(\$('#payment_amount').val()));
  2709.                 let payment_paymentStatus = \$('#payment_paymentStatus').val();
  2710.                 let payment_paymentDate = \$('#payment_paymentDate').val();
  2711.                 let payment_dueDate = \$('#payment_dueDate').val();
  2712.                 let payment_paymentMethod = \$('#payment_paymentMethod').val();
  2713.                 let payment_description = \$('#payment_description').val();
  2714.                 if (amount <= 0 || !payment_paymentStatus || !payment_paymentDate || !payment_dueDate || !payment_paymentMethod || !payment_description) {
  2715.                     throw new Error(\"Formdaki eksikleri tamamlayın lütfen\")
  2716.                 }
  2717.                 payment = {
  2718.                     uuid: crypto.randomUUID(),
  2719.                     amount: amount,
  2720.                     status: payment_paymentStatus,
  2721.                     paymentDate: payment_paymentDate,
  2722.                     paymentDueDate: payment_dueDate,
  2723.                     paymentMethod: payment_paymentMethod,
  2724.                     description: payment_description,
  2725.                     voucherCode: \$('#payment_voucherCode').val()
  2726.                 }
  2727.                 payments.push(payment);
  2728.                 fetchPaymentForm();
  2729.                 // Trigger update to show AVOIR if needed
  2730.                 fetchSoldListRows();
  2731.             });
  2732.             // Ödeme satırını silme işlemi
  2733.             \$(document).on('click', '.delete-payment', function() {
  2734.                 \$row = \$(this).closest('tr');
  2735.                 let id = \$row.attr(\"id\");
  2736.                 payments = payments.filter(payment => payment.uuid !== id);
  2737.                 fetchPaymentForm();
  2738.                 // Trigger update to remove AVOIR if needed
  2739.                 fetchSoldListRows();
  2740.             });
  2741.             // Ödeme formunu güncelleme
  2742.             function fetchPaymentForm() {
  2743.                 \$('#payment-list-table-tbody').empty();
  2744.                 payments.forEach(function(val) {
  2745.                     var newRow = `<tr id=\"\${val.uuid}\">
  2746.                         <td><input type=\"text\" class=\"form-control payment-amount payment-amount-input\" value=\"\${addCommas(val.amount) || ''}\" name=\"paymentAmount[]\" placeholder=\"Miktar\"></td>
  2747.                         <td>
  2748.                             <select class=\"form-control\" name=\"paymentStatus[]\">
  2749.                                 <option value=\"0\" \${val.status === \"0\" ? 'selected' : ''}>";
  2750.         // line 2492
  2751.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("payment_status.paid", [], "messages");
  2752.         yield "</option>
  2753.                                 <option value=\"1\" \${val.status === \"1\" ? 'selected' : ''}>";
  2754.         // line 2493
  2755.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("payment_status.not_paid", [], "messages");
  2756.         yield "</option>
  2757.                                 <option value=\"2\" \${val.status === \"2\" ? 'selected' : ''}>";
  2758.         // line 2494
  2759.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("payment_status.term_sale", [], "messages");
  2760.         yield "</option>
  2761.                             </select>
  2762.                         </td>
  2763.                         <td><input name=\"paymentDate[]\" type=\"date\" class=\"form-control\" value=\"\${val.paymentDate || ''}\" required></td>
  2764.                         <td><input name=\"paymentDueDate[]\" type=\"date\" class=\"form-control\" value=\"\${val.paymentDueDate || ''}\" required></td>
  2765.                         <td>
  2766.                             <select class=\"form-control\" name=\"paymentMethod[]\">
  2767.                                 <option value=\"0\">Ödeme Yöntemi Seçin</option>
  2768.                                 ";
  2769.         // line 2502
  2770.         $context['_parent'] = $context;
  2771.         $context['_seq'] = CoreExtension::ensureTraversable((isset($context["paymentMethods"]) || array_key_exists("paymentMethods"$context) ? $context["paymentMethods"] : (function () { throw new RuntimeError('Variable "paymentMethods" does not exist.'2502$this->source); })()));
  2772.         foreach ($context['_seq'] as $context["_key"] => $context["paymentMethod"]) {
  2773.             // line 2503
  2774.             yield "                                <option value=\"";
  2775.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["paymentMethod"], "id", [], "any"falsefalsefalse2503), "html"nulltrue);
  2776.             yield "\" \${val.paymentMethod === '";
  2777.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["paymentMethod"], "id", [], "any"falsefalsefalse2503), "html"nulltrue);
  2778.             yield "' ? 'selected' : ''}>
  2779.                                     ";
  2780.             // line 2504
  2781.             yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["paymentMethod"], "name", [], "any"falsefalsefalse2504), "html"nulltrue);
  2782.             yield "
  2783.                                 </option>
  2784.                                 ";
  2785.         }
  2786.         $_parent $context['_parent'];
  2787.         unset($context['_seq'], $context['_key'], $context['paymentMethod'], $context['_parent']);
  2788.         $context array_intersect_key($context$_parent) + $_parent;
  2789.         // line 2507
  2790.         yield "                            </select>
  2791.                         </td>
  2792.                         <td><input type=\"text\" class=\"form-control\" value=\"\${val.description || ''}\" name=\"description[]\">
  2793.                             <input type=\"hidden\" name=\"voucherCode[]\" value=\"\${val.voucherCode || ''}\">
  2794.                         </td>
  2795.                         <td><button type=\"button\" class=\"btn btn-primary btn-sm save-payment-row\">";
  2796.         // line 2512
  2797.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("save", [], "messages");
  2798.         yield "</button></td>
  2799.                         <td><button type=\"button\" class=\"btn btn-danger btn-sm delete-payment\">";
  2800.         // line 2513
  2801.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("delete", [], "messages");
  2802.         yield "</button></td>
  2803.                     </tr>`;
  2804.                     // Yeni satırı tabloya ekle
  2805.                     \$('#payment-list-table-tbody').append(newRow);
  2806.                     \$('#add-payment-modal').modal(\"hide\");
  2807.                     resetPaymentForm();
  2808.                 });
  2809.                 calculateAndWriteDiffBetweenPaymentAndSolds();
  2810.             }
  2811.             function updatePaymentByUUID(uuid, updatedData) {
  2812.                 const paymentIndex = payments.findIndex(payment => payment.uuid === uuid);
  2813.                 if (paymentIndex === -1) {
  2814.                     console.error(`Payment with UUID \${uuid} not found!`);
  2815.                     return false;
  2816.                 }
  2817.                 payments[paymentIndex] = {
  2818.                     ...payments[paymentIndex], // Mevcut veriler
  2819.                     ...updatedData // Yeni veriler
  2820.                 };
  2821.                 fetchPaymentForm();
  2822.                 return true;
  2823.             }
  2824.             function calculateAndWriteDiffBetweenPaymentAndSolds(existingTotals = null) {
  2825.                 const totals = existingTotals || aggregateSoldTotals();
  2826.                 const saleTotalRounded = totals.grandTotalRounded;
  2827.                 const paymentTotal = convertToDecimal(calculateTotalPaymentAmount());
  2828.                 const diff = totals.grandTotal.minus(paymentTotal);
  2829.                 const diffRounded = diff.toDecimalPlaces(2, MONEY_ROUNDING_MODE);
  2830.                 \$('#total-amount-span').html(addCommas(saleTotalRounded.toFixed(2)));
  2831.                 \$('#remainder-amount-span').html(addCommas(diffRounded.toFixed(2)));
  2832.             }
  2833.             function resetPaymentForm() {
  2834.                 \$('#payment_amount').val('');
  2835.                 \$('#payment_description').val('');
  2836.                 \$('#payment_voucherCode').val('');
  2837.                 \$('#payment_voucherCode').closest('.form-group').hide(); // Reset visibility
  2838.             }
  2839.             \$(document).on('click', '.save-payment-row', function() {
  2840.                 const \$row = \$(this).closest('tr');
  2841.                 const uuid = \$row.attr('id');
  2842.                 const updatedData = {
  2843.                     amount: convertToDecimal(\$row.find('input[name=\"paymentAmount[]\"]').val().replace(',', '')).toNumber(),
  2844.                     status: \$row.find('select[name=\"paymentStatus[]\"]').val(),
  2845.                     paymentDate: \$row.find('input[name=\"paymentDate[]\"]').val(),
  2846.                     paymentDueDate: \$row.find('input[name=\"paymentDueDate[]\"]').val(),
  2847.                     paymentMethod: \$row.find('select[name=\"paymentMethod[]\"]').val(),
  2848.                     description: \$row.find('input[name=\"description[]\"]').val(),
  2849.                     voucherCode: \$row.find('input[name=\"voucherCode[]\"]').val()
  2850.                 };
  2851.                 const result = updatePaymentByUUID(uuid, updatedData);
  2852.                 if (result) {
  2853.                     showSuccessAlert(\"Ödeme satırı güncellendi :\", updatedData);
  2854.                 } else {
  2855.                     console.log(\"Failed to update payment.\");
  2856.                 }
  2857.             });
  2858.             function resetAddProductForm() {
  2859.                 \$('#products_sold_quantity').val(0);
  2860.                 \$('#products_sold_totalUnitPurchasePrice').val(0);
  2861.                 \$('#products_sold_unAllocatedQuantity').val(0);
  2862.                 \$('#products_sold_totalPuchasePrice').val(0);
  2863.             }
  2864.             function calculatePrice() {
  2865.                 var quantityP = convertToFloat(\$('#products_sold_quantity').val());
  2866.                 var unAllocatedQuantityP = convertToFloat(\$('#products_sold_unAllocatedQuantity').val());
  2867.                 var totalUnitPurchasePriceP = convertToFloat(\$('#products_sold_totalUnitPurchasePrice').val());
  2868.                 var taxP = convertToFloat(\$('#products_sold_tax').val());
  2869.                 var discountP = convertToFloat(\$('#products_sold_discount').val());
  2870.                 var totalAmount = (quantityP + unAllocatedQuantityP) * totalUnitPurchasePriceP;
  2871.                 var discountedAmount = totalAmount - (totalAmount * (discountP / 100));
  2872.                 var finalAmount = discountedAmount + (discountedAmount * (taxP / 100));
  2873.                 finalAmount = roundToTwoDecimals(finalAmount);
  2874.                 \$('#products_sold_totalPuchasePrice').val(finalAmount);
  2875.             }
  2876.             \$(document).on('change', '#products_sold_tax', calculatePrice);
  2877.             \$(document).on('change', '#products_sold_discount', calculatePrice);
  2878.             \$(document).on('change', '#products_sold_quantity', calculatePrice);
  2879.             \$(document).on('change', '#products_sold_totalUnitPurchasePrice', calculatePrice);
  2880.             function roundToTwoDecimals(number) {
  2881.                 var factor = Math.pow(10, 2);
  2882.                 return (Math.round(number * factor) / factor).toFixed(2);
  2883.             }
  2884.             function validate(s) {
  2885.                 var rgx = /^[0-9]*\\.?[0-9]*\$/;
  2886.                 return s.match(rgx);
  2887.             }
  2888.             function convertToFloat(value) {
  2889.                 if (typeof value === \"string\") {
  2890.                     value = value.replace(',', '');
  2891.                 }
  2892.                 return parseFloat(value);
  2893.             }
  2894.             \$(document).on('change', 'input[name=\"totalUnitPurchasePrice[]\"]', function() {
  2895.                 var unitPrice = \$(this).val();
  2896.             });
  2897.             var productCode = 0;
  2898.             \$('#productselect').on('change', function() {
  2899.                 \$.ajax({
  2900.                     url: \"/stock-detail/\" + \$('#productselect option:selected').val(),
  2901.                     dataType: 'JSON',
  2902.                     method: 'GET',
  2903.                     success: function(response) {
  2904.                         var productid = response.productid;
  2905.                         var product = products.find(function(item) {
  2906.                             return item.productid === productid;
  2907.                         });
  2908.                         product.length = response.length;
  2909.                         product.priceFob = response.priceFob;
  2910.                         product.priceNavlun = response.priceNavlun;
  2911.                         product.totalQuantity = response.totalQuantity;
  2912.                         product.quantity = response.quantity;
  2913.                         product.unAllocatedQuantity = response.unAllocatedQuantity;
  2914.                         product.thickness = response.thickness;
  2915.                         product.totalUnitPrice = response.totalUnitPrice;
  2916.                         product.width = response.width;
  2917.                         selectProduct(product.productid);
  2918.                         getProductCost(product.productid);
  2919.                         fetchStocks();
  2920.                         productname.val(product.name);
  2921.                         productmeasurement.val(product.measurement);
  2922.                         productCode = product.code;
  2923.                         unitPriceFob.val(addCommas(product.priceFob));
  2924.                         unitPricenavlun.val(addCommas(product.priceNavlun));
  2925.                         totalUnitPrice.val(addCommas(product.priceNavlun + response.priceFob));
  2926.                         totalQuantity = product.totalQuantity;
  2927.                         productId = product.productid;
  2928.                         // Seçilen ürün için birimleri yükle ve ana birimi seç
  2929.                         fillUnitSelects(product);
  2930.                         computeAndShowBaseUnitEquivalent();
  2931.                     },
  2932.                     error: function(error) {
  2933.                         // Hata yönetimi
  2934.                     }
  2935.                 });
  2936.             });
  2937.             function isProductService(productId){
  2938.                 const product = products.find(product => product.productid === productId);
  2939.                 const productType = product.productType.key;
  2940.                 if(productType === \"INSTALLATION_SERVICE\" || productType === \"MAINTENANCE_SERVICE\" || productType === \"CONSULTATION_SERVICE\" || productType === 'TREE'){
  2941.                     return true;
  2942.                 }
  2943.                 return false;
  2944.             }
  2945.             // TODO
  2946.             \$('#add-product-row-btn').on('click', function() {
  2947.                 var productId = \$('#productselect').val();
  2948.                 if (!productId || productId <= 0) {
  2949.                     showErrorAlert(\"Ürün seçimi yapın\");
  2950.                     return;
  2951.                 }
  2952.                 let product = getSelectedProduct();
  2953.                 const productType = product.productType.key;
  2954.                 var quantity = \$('#adder-allocated-quantity').val();
  2955.                 var unAllocatedQuantity = \$('#adder-unallocated-quantity').val();
  2956.                 var unitPrice = \$('#adder-price').val();
  2957.                 var tax = \$('#adder-tva-select').val();
  2958.                 var discount = \$('#adder-discount-select').val();
  2959.                 var totalPurchasePrice = \$('#adder-total').val();
  2960.                 quantity = convertToDecimal(quantity);
  2961.                 unAllocatedQuantity = convertToDecimal(unAllocatedQuantity);
  2962.                 unitPrice = convertToDecimal(unitPrice);
  2963.                 tax = convertToDecimal(tax);
  2964.                 discount = convertToDecimal(discount);
  2965.                 totalPurchasePrice = convertToDecimal(totalPurchasePrice);
  2966.                 if(productType === 'TREE') {
  2967.                 }
  2968.                 checkStockQuantity(quantity);
  2969.                 const selectedUnitId = \$('#adder-quantity-unit-select').val();
  2970.                 if (!selectedUnitId || String(selectedUnitId) === '') {
  2971.                     showErrorAlert('Lütfen birim seçiniz.');
  2972.                     return;
  2973.                 }
  2974.                 const item =  addProductToSoldList(
  2975.                                     product.productid,
  2976.                                     product.name,
  2977.                                     product.code,
  2978.                                     product.measurement,
  2979.                                     quantity,
  2980.                                     unitPrice,
  2981.                                     tax,
  2982.                                     discount,
  2983.                                     totalPurchasePrice,
  2984.                                     product.warehouseid,
  2985.                                     unAllocatedQuantity,
  2986.                                     product.thickness,
  2987.                                     product.width,
  2988.                                     product.length,
  2989.                                     product.cost,
  2990.                                     product.productType,
  2991.                                     selectedUnitId,
  2992.                                 );
  2993.                 if(isProductService(product.productid)){
  2994.                     \$('#update_service_id').val(item.uuid);
  2995.                     \$('#updateServiceModal').modal('show');
  2996.                 }else{
  2997.                   if(quantity.toNumber() === 0 && unAllocatedQuantity.toNumber() === 0) {
  2998.                     showErrorAlert(\"Miktar veya tahsis edilmemiş miktar 0 olamaz\");
  2999.                     return;
  3000.                   }
  3001.                 }
  3002.                 fetchSoldListRows();
  3003.                 resetAdderRow();
  3004.             });
  3005.             \$('#service_modal_save_changes_btn').on('click', function() {
  3006.                 const uuid = \$('#update_service_id').val();
  3007.                 const soldProduct = soldList.find(soldProduct => soldProduct.uuid === uuid);
  3008.                 const product  = products.find(product => product.productid === soldProduct.productid);
  3009.                 const productType = product.productType.key;
  3010.                 // Modal değerlerini geri alıp objeye yazıyoruz
  3011.                 soldProduct.productName = \$('#update_service_name').val();
  3012.                 soldProduct.cost = parseFloat(\$('#update_service_cost').val());
  3013.                 soldProduct.description = \$('#update_service_description').val();
  3014.                 const tr = \$('#' + uuid);
  3015.                 console.log(\"Servis güncellendi:\", soldProduct);
  3016.                 \$('#updateServiceModal').modal('hide');
  3017.                 // Rows'ları yeniden render et ki service adı dropdown'da görünsün
  3018.                 fetchSoldListRows();
  3019.                 updateTotalAmounts();
  3020.                 if(isProductService(product.productid)){
  3021.                     addServiceEditButtonIfNeeded(uuid);
  3022.                 }
  3023.             });
  3024.             \$(document).on('click', '.edit-service-button', function () {
  3025.                 const uuid = \$(this).data('uuid');
  3026.                 const soldProduct = soldList.find(sp => sp.uuid === uuid);
  3027.                 \$('#update_service_id').val(uuid);
  3028.                 \$('#update_service_name').val(soldProduct?.productName || \"\");
  3029.                 \$('#update_service_cost').val(soldProduct?.cost || \"0.00\");
  3030.                 \$('#update_service_description').val(soldProduct?.description || \"\");
  3031.                 \$('#updateServiceModal').modal('show');
  3032.             });
  3033.             // TODO:
  3034.             function addServiceEditButtonIfNeeded(uuid) {
  3035.                 const soldProduct = soldList.find(sp => sp.uuid === uuid);
  3036.                 const product = products.find(p => p.productid === soldProduct.productid);
  3037.                 const productType = product.productType.key;
  3038.                 // Sadece ürün service ise buton ekle
  3039.                 if (product && isProductService(product.productid)) {
  3040.                     const tr = \$('#' + uuid);
  3041.                     // Eğer daha önce eklenmediyse ekle
  3042.                     if (tr.find('.edit-service-button').length === 0) {
  3043.                         const btn = `
  3044.                             <button type=\"button\"
  3045.                                     class=\"btn btn-warning btn-sm edit-service-button\"
  3046.                                     data-uuid=\"\${uuid}\"
  3047.                                     title=\"Servisi Güncelle\">
  3048.                                 <i class=\"fas fa-edit\"></i>
  3049.                             </button>`;
  3050.                         // örnek: sil butonunun yanına ekleyelim
  3051.                         tr.find('.btn-group').prepend(btn);
  3052.                     }
  3053.                 }
  3054.             }
  3055.             // Reset adder row form after adding product
  3056.             function resetAdderRow() {
  3057.                 \$('#productselect').val('').trigger('change');
  3058.                 \$('#adder-allocated-quantity').val('0');
  3059.                 \$('#adder-unallocated-quantity').val('0');
  3060.                 \$('#adder-price').val('0');
  3061.                 \$('#adder-discount-select').val('0');
  3062.                 \$('#adder-tva-select').val('0');
  3063.                 \$('#adder-total').val('0');
  3064.                 \$('#unalloc-display').text('0');
  3065.                 clearUnitSelects();
  3066.                 \$('#info-details-content').hide();
  3067.                 \$('#show-info-btn i').removeClass('fa-chevron-up').addClass('fa-info-circle');
  3068.             }
  3069.             // =============================================================================
  3070.             // EVENT HANDLERS FOR SALES LIST EDITING
  3071.             // =============================================================================
  3072.             // Show/hide product info details
  3073.             \$(document).on('click', '.show-row-info-btn', function() {
  3074.                 const \$infoContent = \$(this).closest('tr').next('.info-details-row-class').find('.info-details-content-class');
  3075.                 const \$icon = \$(this).find('i');
  3076.                 if (\$infoContent.is(':visible')) {
  3077.                     \$infoContent.hide();
  3078.                     \$icon.removeClass('fa-chevron-up').addClass('fa-info-circle');
  3079.                     \$(this).closest('tr').next('.info-details-row-class').hide();
  3080.                 } else {
  3081.                     \$infoContent.show();
  3082.                     \$icon.removeClass('fa-info-circle').addClass('fa-chevron-up');
  3083.                     \$(this).closest('tr').next('.info-details-row-class').show();
  3084.                 }
  3085.             });
  3086.             \$(document).on('change', '.product-select-row', function() {
  3087.                 const uuid = \$(this).data('uuid');
  3088.                 const newProductId = parseInt(\$(this).val());
  3089.                 const soldItemIndex = soldList.findIndex(item => item.uuid === uuid);
  3090.                 if (soldItemIndex > -1) {
  3091.                     const newProduct = products.find(p => p.productid === newProductId);
  3092.                     if (newProduct) {
  3093.                         soldList[soldItemIndex].productid = newProduct.productid;
  3094.                         soldList[soldItemIndex].productName = newProduct.name;
  3095.                         soldList[soldItemIndex].code = newProduct.code;
  3096.                         soldList[soldItemIndex].measurement = newProduct.measurement;
  3097.                         soldList[soldItemIndex].cost = newProduct.cost;
  3098.                     }
  3099.                     fetchSoldListRows();
  3100.                     updateTotalAmounts();
  3101.                 }
  3102.                 console.table(soldList);
  3103.             });
  3104.             // Handle unit price changes in sold list rows
  3105.             \$(document).on('input change', '.price-input-row', function() {
  3106.                 const uuid = \$(this).data('uuid');
  3107.                 const value = \$(this).val();
  3108.                 // Birim fiyat manuel değiştirildi, artık otomatik hesaplama yapılmalı
  3109.                 delete rowHasManualTotal[uuid];
  3110.                 updateSoldListItem(uuid, 'unitPrice', value);
  3111.             });
  3112.             // Handle discount changes in sold list rows
  3113.             \$(document).on('change', '.discount-select-row', function() {
  3114.                 const uuid = \$(this).data('uuid');
  3115.                 const value = \$(this).val();
  3116.                 // İndirim değiştirildi, artık otomatik hesaplama yapılmalı
  3117.                 delete rowHasManualTotal[uuid];
  3118.                 updateSoldListItem(uuid, 'discount', value);
  3119.             });
  3120.             // Handle tax changes in sold list rows
  3121.             \$(document).on('change', '.tax-select-row', function() {
  3122.                 const uuid = \$(this).data('uuid');
  3123.                 const value = \$(this).val();
  3124.                 // KDV değiştirildi, artık otomatik hesaplama yapılmalı
  3125.                 delete rowHasManualTotal[uuid];
  3126.                 updateSoldListItem(uuid, 'tax', value);
  3127.             });
  3128.             // Handle unit selection changes in sold list rows
  3129.             \$(document).on('change', '.quantity-unit-select', function() {
  3130.                 const uuid = \$(this).data('uuid');
  3131.                 const unitId = \$(this).val();
  3132.                 const \$quantityInput = \$(`.quantity-input-row[data-uuid=\"\${uuid}\"]`);
  3133.                 const currentQuantity = parseFloat(\$quantityInput.val()) || 0;
  3134.                 // Update the selected unit in sold list
  3135.                 const itemIndex = soldList.findIndex(item => item.uuid === uuid);
  3136.                 if (itemIndex !== -1) {
  3137.                     const item = soldList[itemIndex];
  3138.                     const oldUnitId = item.selectedUnitId;
  3139.                     item.selectedUnitId = unitId;
  3140.                     // Show unit conversion equivalent
  3141.                     showUnitConversionForRow(uuid, item.productid, currentQuantity, unitId);
  3142.                     // If changing from one unit to another, convert the quantity
  3143.                     if (oldUnitId && oldUnitId !== unitId && unitId && currentQuantity > 0) {
  3144.                         convertQuantityBetweenUnits(item.productid, currentQuantity, oldUnitId, unitId, function(convertedQuantity) {
  3145.                             if (convertedQuantity !== null) {
  3146.                                 \$quantityInput.val(convertedQuantity.toFixed(2));
  3147.                                 updateSoldListItem(uuid, 'quantity', convertedQuantity);
  3148.                                 // Update conversion display with new quantity
  3149.                                 showUnitConversionForRow(uuid, item.productid, convertedQuantity, unitId);
  3150.                             }
  3151.                         });
  3152.                     }
  3153.                     // Recompute and store base unit quantity for the row
  3154.                     computeBaseUnitQuantity(item.productid, unitId, parseFloat(\$quantityInput.val()) || 0, function(baseQty){
  3155.                         const idx = soldList.findIndex(sp => sp.uuid === uuid);
  3156.                         if(idx !== -1){ soldList[idx].baseUnitQuantity = convertToDecimal(baseQty || 0).toNumber(); }
  3157.                     });
  3158.                 }
  3159.             });
  3160.             // Handle quantity changes in sold list rows to update conversion display
  3161.             \$(document).on('input change', '.quantity-input-row', function() {
  3162.                 const uuid = \$(this).data('uuid');
  3163.                 const value = \$(this).val();
  3164.                 const item = soldList.find(item => item.uuid === uuid);
  3165.                 if (item && item.selectedUnitId) {
  3166.                     showUnitConversionForRow(uuid, item.productid, parseFloat(value) || 0, item.selectedUnitId);
  3167.                 }
  3168.                 // Miktar manuel değiştirildi, artık otomatik hesaplama yapılmalı
  3169.                 delete rowHasManualTotal[uuid];
  3170.                 updateSoldListItem(uuid, 'quantity', value);
  3171.                 // Also refresh baseUnitQuantity on quantity change
  3172.                 if (item) {
  3173.                     computeBaseUnitQuantity(item.productid, item.selectedUnitId, parseFloat(value) || 0, function(baseQty){
  3174.                         const idx = soldList.findIndex(sp => sp.uuid === uuid);
  3175.                         if(idx !== -1){ soldList[idx].baseUnitQuantity = convertToDecimal(baseQty || 0).toNumber(); }
  3176.                     });
  3177.                 }
  3178.             });
  3179.             // Show unit conversion equivalent for a specific row
  3180.             function showUnitConversionForRow(uuid, productId, quantity, fromUnitId) {
  3181.                 if (!fromUnitId || !quantity || quantity <= 0) {
  3182.                     updateRowQuantityHint(uuid, '');
  3183.                     return;
  3184.                 }
  3185.                 const product = products.find(p => p.productid === productId);
  3186.                 if (!product || !product.measurementUnitId) {
  3187.                     updateRowQuantityHint(uuid, '');
  3188.                     return;
  3189.                 }
  3190.                 // If already in product's main unit, no conversion needed
  3191.                 if (fromUnitId == product.measurementUnitId) {
  3192.                     updateRowQuantityHint(uuid, '');
  3193.                     return;
  3194.                 }
  3195.                 \$.ajax({
  3196.                     url: '/admin/measurement/convert-to-product-unit',
  3197.                     method: 'POST',
  3198.                     dataType: 'json',
  3199.                     data: {
  3200.                         productId: productId,
  3201.                         fromUnitId: fromUnitId,
  3202.                         quantity: quantity
  3203.                     },
  3204.                     success: function(resp) {
  3205.                         if (resp && resp.success) {
  3206.                             const unitText = product.measurementUnit ? (' ' + product.measurementUnit) : '';
  3207.                             updateRowQuantityHint(uuid, (Number(resp.result).toFixed(2)) + unitText);
  3208.                 } else {
  3209.                             updateRowQuantityHint(uuid, '');
  3210.                         }
  3211.                     },
  3212.                     error: function() {
  3213.                         updateRowQuantityHint(uuid, '');
  3214.                     }
  3215.                 });
  3216.             }
  3217.             // Update quantity hint for a specific row
  3218.             function updateRowQuantityHint(uuid, text) {
  3219.                 let \$hint = \$(`.quantity-conversion-hint[data-uuid=\"\${uuid}\"]`);
  3220.                 if (\$hint.length === 0) {
  3221.                     const \$quantityCell = \$(`.quantity-input-row[data-uuid=\"\${uuid}\"]`).closest('td');
  3222.                     \$quantityCell.append(`<small class=\"form-text text-muted quantity-conversion-hint\" data-uuid=\"\${uuid}\"></small>`);
  3223.                     \$hint = \$(`.quantity-conversion-hint[data-uuid=\"\${uuid}\"]`);
  3224.                 }
  3225.                 \$hint.text(text || '');
  3226.             }
  3227.             // Convert quantity between different measurement units
  3228.             function convertQuantityBetweenUnits(productId, quantity, fromUnitId, toUnitId, callback) {
  3229.                 if (!fromUnitId || !toUnitId || fromUnitId === toUnitId) {
  3230.                     callback(quantity);
  3231.                     return;
  3232.                 }
  3233.                 \$.ajax({
  3234.                     url: '/admin/measurement/convert-between-units',
  3235.                     method: 'POST',
  3236.                     dataType: 'json',
  3237.                     data: {
  3238.                         productId: productId,
  3239.                         fromUnitId: fromUnitId,
  3240.                         toUnitId: toUnitId,
  3241.                         quantity: quantity
  3242.                     },
  3243.                     success: function(resp) {
  3244.                         if (resp && resp.success) {
  3245.                             callback(parseFloat(resp.result));
  3246.                 } else {
  3247.                             console.error('Unit conversion failed:', resp);
  3248.                             callback(null);
  3249.                         }
  3250.                     },
  3251.                     error: function() {
  3252.                         console.error('Unit conversion request failed');
  3253.                         callback(null);
  3254.                     }
  3255.                 });
  3256.             }
  3257.             // Handle total price changes (reverse calculation to unit price)
  3258.             \$(document).on('change blur', '.total-input-row', function() {
  3259.                 updateUnitPriceFromTotal(\$(this).data('uuid'));
  3260.             });
  3261.             // Handle delete row button clicks
  3262.             const currencySymbol = \"";
  3263.         // line 3057
  3264.         yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->extensions['Symfony\Bridge\Twig\Extension\TranslationExtension']->trans("currency.symbol"), "js"), "html"nulltrue);
  3265.         yield "\";
  3266.             const PAYMENT_TOLERANCE = 0.01;
  3267.             const AUTO_PAYMENT_DESCRIPTION = 'Sistem tarafından ödeme otomatik oluşturuldu';
  3268.             const AUTO_PAYMENT_STATUS_TEXT = 'Ödendi';
  3269.             let autoPaymentModalState = null;
  3270.             let cachedCashPaymentMethod = null;
  3271.             function detectCashPaymentMethod() {
  3272.                 const \$options = \$('#payment_paymentMethod option');
  3273.                 let fallback = null;
  3274.                 let cashCandidate = null;
  3275.                 \$options.each(function() {
  3276.                     const \$option = \$(this);
  3277.                     const value = (\$option.val() || '').trim();
  3278.                     if (!value) {
  3279.                         return;
  3280.                     }
  3281.                     if (!fallback) {
  3282.                         fallback = { id: value, label: (\$option.text() || '').trim() };
  3283.                     }
  3284.                     const label = (\$option.text() || '').toLowerCase();
  3285.                     if (label.includes('cash') || label.includes('nakit')) {
  3286.                         cashCandidate = { id: value, label: (\$option.text() || '').trim() };
  3287.                         return false;
  3288.                     }
  3289.                 });
  3290.                 if (cashCandidate) {
  3291.                     return cashCandidate;
  3292.                 }
  3293.                 if (fallback) {
  3294.                     return fallback;
  3295.                 }
  3296.                 return { id: '1', label: 'Cash' };
  3297.             }
  3298.             function ensureCashPaymentMethod() {
  3299.                 if (!cachedCashPaymentMethod) {
  3300.                     cachedCashPaymentMethod = detectCashPaymentMethod();
  3301.                 }
  3302.                 return cachedCashPaymentMethod;
  3303.             }
  3304.             function normalizeCurrency(value) {
  3305.                 return convertToDecimal(value).toDecimalPlaces(2, Decimal.ROUND_HALF_UP).toNumber();
  3306.             }
  3307.             function formatCurrency(value) {
  3308.                 const normalized = normalizeCurrency(value);
  3309.                 const formatted = addCommas(normalized.toFixed(2));
  3310.                 return formatted.replace(/,/g, '#').replace(/\\./g, ',').replace(/#/g, '.') + ' ' + currencySymbol;
  3311.             }
  3312.             function calculateTotalPaymentAmount() {
  3313.                 let total = new Decimal(0);
  3314.                 payments.forEach(function(payment) {
  3315.                     total = total.plus(convertToDecimal(payment.amount));
  3316.                 });
  3317.                 return total.toNumber();
  3318.             }
  3319.             function getSaleDateValue() {
  3320.                 const saleDate = \$('#sales_form_salesDate').val();
  3321.                 if (saleDate && saleDate.trim() !== '') {
  3322.                     return saleDate;
  3323.                 }
  3324.                 return new Date().toISOString().split('T')[0];
  3325.             }
  3326.             function createAutoPaymentPayload(amount, saleDate) {
  3327.                 const method = ensureCashPaymentMethod();
  3328.                 return {
  3329.                     uuid: crypto.randomUUID(),
  3330.                     amount: normalizeCurrency(amount),
  3331.                     status: '0',
  3332.                     paymentDate: saleDate,
  3333.                     paymentDueDate: saleDate,
  3334.                     paymentMethod: method.id,
  3335.                     description: AUTO_PAYMENT_DESCRIPTION
  3336.                 };
  3337.             }
  3338.             function openAutoPaymentModal(config) {
  3339.                 autoPaymentModalState = {
  3340.                     scenario: config.scenario,
  3341.                     amount: normalizeCurrency(config.amount),
  3342.                     saleDate: config.saleDate,
  3343.                     saleTotal: normalizeCurrency(config.saleTotal),
  3344.                     currentPayments: normalizeCurrency(config.currentPayments)
  3345.                 };
  3346.                 const method = ensureCashPaymentMethod();
  3347.                 let message = '';
  3348.                 if (config.scenario === 'no-payment') {
  3349.                     message = 'Bu satış için henüz ödeme girilmedi. Aşağıdaki bilgilerle otomatik bir nakit ödeme oluşturulacaktır.';
  3350.                 } else {
  3351.                     message = 'Girilen ödemeler satış toplamı ile uyumsuz. Eksik tutar otomatik bir nakit ödeme olarak eklenecektir.';
  3352.                 }
  3353.                 \$('#auto-payment-message').text(message);
  3354.                 \$('#auto-payment-sale-total').text(formatCurrency(autoPaymentModalState.saleTotal));
  3355.                 \$('#auto-payment-current-payments').text(formatCurrency(autoPaymentModalState.currentPayments));
  3356.                 \$('#auto-payment-amount').text(formatCurrency(autoPaymentModalState.amount));
  3357.                 \$('#auto-payment-method').text(method.label);
  3358.                 \$('#auto-payment-status').text(AUTO_PAYMENT_STATUS_TEXT);
  3359.                 \$('#auto-payment-description').text(AUTO_PAYMENT_DESCRIPTION);
  3360.                 \$('#confirm-auto-payment').prop('disabled', false);
  3361.                 \$('#autoPaymentModal').modal('show');
  3362.             }
  3363.             function validateSalesForm() {
  3364.                 const form = \$('form[name=\"sales_form\"]');
  3365.                 if (!form || form.length === 0) {
  3366.                     return true;
  3367.                 }
  3368.                 return form[0].reportValidity();
  3369.             }
  3370.             function submitSalesRequest() {
  3371.                 if (!validateSalesForm()) {
  3372.                     return;
  3373.                 }
  3374.                 const salesData = {
  3375.                     payments: payments,
  3376.                     soldList: soldList,
  3377.                     invoice: {
  3378.                         invoiceNumber: \$('#sales_form_invoiceNumber').val(),
  3379.                         customer: \$('#sales_form_customer').val(),
  3380.                         paymentStatus: \$('#sales_form_paymentStatus').val(),
  3381.                         salesDate: \$('#sales_form_salesDate').val(),
  3382.                         deliveryDate: \$('#sales_form_deliveryDate').val(),
  3383.                         dueDate: \$('#sales_form_dueDate').val(),
  3384.                         validDate: \$('#sales_form_validDate').val(),
  3385.                         seller: \$('#sales_form_seller').val(),
  3386.                         description: \$('#sales_form_description').val(),
  3387.                         shippingNotes: \$('#sales_form_shippingNotes').val(),
  3388.                         paymentNotes: \$('#sales_form_paymentNotes').val(),
  3389.                         salesType: \$('input[name=\"salesType\"]').filter(':checked').val() || 'proforma',
  3390.                         salesStatus: \$('#sales_form_status').val() ? \$('#sales_form_status').val() : '0'
  3391.                     }
  3392.                 };
  3393.                 \$.ajax({
  3394.                     url: \"";
  3395.         // line 3203
  3396.         yield $this->extensions['Symfony\Bridge\Twig\Extension\RoutingExtension']->getPath("app_admin_sales_create");
  3397.         yield "\",
  3398.                     method: 'POST',
  3399.                     data: salesData,
  3400.                     success: function(response) {
  3401.                         window.location.href = \"/sales/detail/\" + response.id;
  3402.                         Swal.fire({
  3403.                             icon: 'success',
  3404.                             title: 'Başarılı',
  3405.                             text: 'Satış başarıyla oluşturuldu'
  3406.                         });
  3407.                     },
  3408.                     error: function(xhr) {
  3409.                         var response = JSON.parse(xhr.responseText);
  3410.                         showErrorAlert(response.message);
  3411.                     }
  3412.                 });
  3413.             }
  3414.             function finalizeSalesSubmission() {
  3415.                 const saleTotal = convertToDecimal(getTotalSoldAmount());
  3416.                 const totalPayments = convertToDecimal(calculateTotalPaymentAmount());
  3417.                 const difference = saleTotal.minus(totalPayments).abs().toNumber();
  3418.                 if (difference > PAYMENT_TOLERANCE) {
  3419.                     showErrorAlert('Ödemeler satış toplamı ile hâlâ uyumsuz. Lütfen kontrol edin.');
  3420.                     return;
  3421.                 }
  3422.                 submitSalesRequest();
  3423.             }
  3424.             \$('#confirm-auto-payment').on('click', function() {
  3425.                 if (!autoPaymentModalState) {
  3426.                     return;
  3427.                 }
  3428.                 const saleDate = autoPaymentModalState.saleDate || getSaleDateValue();
  3429.                 const autoPayment = createAutoPaymentPayload(autoPaymentModalState.amount, saleDate);
  3430.                 payments.push(autoPayment);
  3431.                 fetchPaymentForm();
  3432.                 calculateAndWriteDiffBetweenPaymentAndSolds();
  3433.                 \$('#confirm-auto-payment').prop('disabled', true);
  3434.                 \$('#autoPaymentModal').modal('hide');
  3435.                 autoPaymentModalState = null;
  3436.                 finalizeSalesSubmission();
  3437.             });
  3438.             \$('#autoPaymentModal').on('hidden.bs.modal', function() {
  3439.                 \$('#confirm-auto-payment').prop('disabled', false);
  3440.                 autoPaymentModalState = null;
  3441.             });
  3442.             ensureCashPaymentMethod();
  3443.             \$(document).on('click', '.delete-row-button', function() {
  3444.                 const uuid = \$(this).data('uuid');
  3445.                 deleteProductInSoldList(uuid);
  3446.                 \$(`tr[id=\"\${uuid}\"]`).remove();
  3447.                 \$(`.info-details-row-class[data-uuid=\"\${uuid}\"]`).remove();
  3448.                 fetchStocks();
  3449.                 updateTotalAmounts();
  3450.                 fetchPaymentForm();
  3451.                 \$('#sales_form_totalPurchasePrice').val(addCommas(getTotalSoldAmount()));
  3452.             });
  3453.              // Handle unallocated quantity modal for rows
  3454.             \$(document).on('click', '.open-unallocated-modal-row', function() {
  3455.                 const uuid = \$(this).data('uuid');
  3456.                 const itemIndex = soldList.findIndex(item => item.uuid === uuid);
  3457.                 if (itemIndex === -1) return;
  3458.                 // Değeri gizli input yerine doğrudan soldList'ten oku
  3459.                 const currentQty = soldList[itemIndex].unAllocatedQuantity || 0;
  3460.                 \$('#modal-unallocated-quantity').val(Number(currentQty).toFixed(2));
  3461.                 // Store current uuid for saving later
  3462.                 \$('#unallocatedModal').data('current-uuid', uuid);
  3463.                 \$('#unallocatedModal').modal('show');
  3464.             });
  3465.             // Save unallocated quantity from modal for rows
  3466.             \$(document).on('click', '#save-unallocated-btn', function() {
  3467.                  const uuid = \$('#unallocatedModal').data('current-uuid');
  3468.                     // Sadece satırlar için olan bölüm (uuid varsa)
  3469.                     if (uuid) {
  3470.                         const qty = \$('#modal-unallocated-quantity').val() || 0;
  3471.                         const newUnallocatedQty = convertToDecimal(qty).toNumber();
  3472.                         // 1. soldList'teki ilgili ürünü bul ve unAllocatedQuantity'yi güncelle
  3473.                         const itemIndex = soldList.findIndex(item => item.uuid === uuid);
  3474.                         if (itemIndex > -1) {
  3475.                             soldList[itemIndex].unAllocatedQuantity = newUnallocatedQty;
  3476.                         }
  3477.                         // 2. DOĞRU SATIRI HEDEFLEYEREK butondaki sayıyı güncelle
  3478.                         const \$button = \$(`.open-unallocated-modal-row[data-uuid=\"\${uuid}\"]`);
  3479.                         \$button.find('.unalloc-display').text(newUnallocatedQty.toFixed(2));
  3480.                         // 3. Tahsis edilmemiş miktar değiştirildi, artık otomatik hesaplama yapılmalı
  3481.                         delete rowHasManualTotal[uuid];
  3482.                         // 4. Satırın genel toplamlarını ve stokları güncelle
  3483.                         updateSoldProductFromRow(uuid);
  3484.                         \$('#unallocatedModal').modal('hide');
  3485.                     } else { // Bu kısım adder-row için, dokunmuyoruz
  3486.                         const qty = \$('#modal-unallocated-quantity').val() || 0;
  3487.                         \$('#adder-unallocated-quantity').val(qty).trigger('change');
  3488.                         \$('#unalloc-display').text(qty);
  3489.                         onInputChange.call(\$('#adder-unallocated-quantity')[0]);
  3490.                         \$('#unallocatedModal').modal('hide');
  3491.                     }
  3492.                             });
  3493.             // Flag to prevent circular updates between unit price and total
  3494.             let isUpdatingFromTotal = false;
  3495.             let isUpdatingFromUnitPrice = false;
  3496.             // adder-row input alanlarının değişikliklerini dinleme
  3497.             \$('#adder-row').on('input change',
  3498.                 '#adder-allocated-quantity, ' +
  3499.                 '#adder-unallocated-quantity, ' +
  3500.                 '#adder-price, ' +
  3501.                 '#adder-discount-select, ' +
  3502.                 '#adder-tva-select, ' +
  3503.                 '#adder-total', onInputChange);
  3504.             // Birim dönüşümünü yazma bittiğinde (blur) ve birim seçiminde (change) yap
  3505.             \$('#adder-row').on('blur', '#adder-allocated-quantity', function(){
  3506.                 computeAndShowBaseUnitEquivalent();
  3507.             });
  3508.             \$('#adder-row').on('change', '#adder-quantity-unit-select', function(){
  3509.                 computeAndShowBaseUnitEquivalent();
  3510.             });
  3511.             // Adder rowdaki input alanlarının değişikliklerini dinleme
  3512.             function onInputChange() {
  3513.                 if(\$(this).attr('id') === 'adder-total') {
  3514.                     // Toplam manuel değiştirildi → birim fiyatı hesapla, ama toplamı tekrar değiştirme
  3515.                     if(isUpdatingFromUnitPrice) return;
  3516.                     isUpdatingFromTotal = true;
  3517.                     const totalAmount = convertToDecimal(\$('#adder-total').val() || 0).toNumber();
  3518.                     const allocatedQuantity = convertToDecimal(\$('#adder-allocated-quantity').val() || 0).toNumber();
  3519.                     const unallocatedQuantity = convertToDecimal(\$('#adder-unallocated-quantity').val() || 0).toNumber();
  3520.                     const discountPercentage = convertToDecimal(((\$('#adder-discount-select').val() || '0') + '').replace('%', '')).toNumber();
  3521.                     const tvaPercentage = convertToDecimal(((\$('#adder-tva-select').val() || '0') + '').replace('%', '')).toNumber();
  3522.                     const unitPrice = calculateUnitPrice(totalAmount, allocatedQuantity, unallocatedQuantity, tvaPercentage, discountPercentage);
  3523.                     \$('#adder-price').val(convertToDecimal(unitPrice).toDecimalPlaces(2, MONEY_ROUNDING_MODE).toFixed(2));
  3524.                     setTimeout(function(){ isUpdatingFromTotal = false; }, 0);
  3525.                 } else {
  3526.                     // Birim fiyat, miktar, indirim veya KDV değişti → toplamı hesapla
  3527.                     if(isUpdatingFromTotal) return;
  3528.                     isUpdatingFromUnitPrice = true;
  3529.                     const allocatedQuantity = convertToDecimal(\$('#adder-allocated-quantity').val() || 0).toNumber();
  3530.                     const unallocatedQuantity = convertToDecimal(\$('#adder-unallocated-quantity').val() || 0).toNumber();
  3531.                     const price = convertToDecimal(\$('#adder-price').val() || 0).toNumber();
  3532.                     const discountPercentage = convertToDecimal(((\$('#adder-discount-select').val() || '0') + '').replace('%', '')).toNumber();
  3533.                     const tvaPercentage = convertToDecimal(((\$('#adder-tva-select').val() || '0') + '').replace('%', '')).toNumber();
  3534.                     calculateTotal(allocatedQuantity, unallocatedQuantity, price, tvaPercentage, discountPercentage);
  3535.                     setTimeout(function(){ isUpdatingFromUnitPrice = false; }, 0);
  3536.                 }
  3537.             }
  3538.             function roundToNearestCent(amount) {
  3539.                 return Math.round(amount * 100) / 100;
  3540.             }
  3541.             // Toplam tutarı hesaplama
  3542.             // Her ara adımda virgülden sonra 2 hane gösterilecek, 3. hane 5 ve üzeri ise yukarı yuvarlanacak
  3543.             function calculateTotal(allocatedQuantity, unallocatedQuantity, price, tvaPercentage, discountPercentage) {
  3544.                 const totals = calculateRowFinancials({
  3545.                     quantity: allocatedQuantity,
  3546.                     unAllocatedQuantity: unallocatedQuantity,
  3547.                     unitPrice: price,
  3548.                     discount: discountPercentage,
  3549.                     tax: tvaPercentage
  3550.                 });
  3551.                 \$('#adder-total').val(totals.totalRounded.toFixed(2));
  3552.             }
  3553.             // Toplam tutardan Birim fiyatı hesaplama
  3554.             function calculateUnitPrice(totalAmount, allocatedQuantity, unallocatedQuantity, tvaPercentage, discountPercentage) {
  3555.                 const totalQuantity = convertToDecimal(allocatedQuantity || 0).plus(convertToDecimal(unallocatedQuantity || 0));
  3556.                 if (totalQuantity.isZero()) {
  3557.                     return 0;
  3558.                 }
  3559.                 const total = convertToDecimal(totalAmount || 0);
  3560.                 // Eğer toplam 0 ise, birim fiyat da 0 olmalı
  3561.                 if (total.isZero()) {
  3562.                     return 0;
  3563.                 }
  3564.                 const discountMultiplier = new Decimal(1).minus(convertToDecimal(discountPercentage || 0).div(100));
  3565.                 const taxMultiplier = new Decimal(1).plus(convertToDecimal(tvaPercentage || 0).div(100));
  3566.                 // %100 indirimde discountMultiplier = 0 olur, bu durumda birim fiyat hesaplanamaz
  3567.                 // Çünkü total = (unitPrice * quantity * (1 - discount) * (1 + tax))
  3568.                 // discount = 100% ise, unitPrice = 0 olmalı (ya da sonsuz, ama mantıklı olan 0)
  3569.                 if (discountMultiplier.isZero()) {
  3570.                     return 0;
  3571.                 }
  3572.                 if (taxMultiplier.isZero()) {
  3573.                     return 0;
  3574.                 }
  3575.                 // Formül: unitPrice = total / (quantity * (1 - discount%) * (1 + tax%))
  3576.                 const subtotal = total.div(taxMultiplier).div(discountMultiplier);
  3577.                 const unitPrice = subtotal.div(totalQuantity);
  3578.                 return unitPrice.toDecimalPlaces(6, MONEY_ROUNDING_MODE).toNumber();
  3579.             }
  3580.             function getProductCost(pid) {
  3581.                 // Popup için URL burada oluşturuluyor.
  3582.                 const url = '/product-cost/' + pid + '/' + getSelectedProduct().warehouseid;
  3583.                 \$.ajax({
  3584.                     url: \"/product-cost-detail/\" + pid + '?warehouse=' + getSelectedProduct().warehouseid,
  3585.                     method: \"POST\",
  3586.                     dataType: \"JSON\",
  3587.                     success: function(data) {
  3588.                         var product = getSelectedProduct();
  3589.                         product.cost = data.cost;
  3590.                         product.measurementUnit = data.measurement;
  3591.                         \$('.stock-info-span').html(data.stock.toFixed(2).toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, \",\") + \" \" + data.measurement);
  3592.                         \$('.cost-info-span').html(data.cost.toFixed(2).toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, \",\") + \" €\"); // Eski detay butonu kaldırıldı
  3593.                         \$('.measurement-unit-info-span').html(data.measurement);
  3594.                         \$('#hidden-cost-input').val(data.cost);
  3595.                         // \"Maliyet\" popup açıyor maliyet detaylarını gösteriyor.
  3596.                         const detailsHtml = `
  3597.                             <div class=\"row align-items-center\">
  3598.                                 <div class=\"col-md-3\">\${product.name}</div>
  3599.                                 <div class=\"col-md-3\">
  3600.                                     <strong>
  3601.                                         <button type=\"button\" class=\"btn btn-link btn-sm p-0 cost-popup-btn\" data-url=\"\${url}\">Maliyet: \${data.cost.toFixed(2)} €</button>
  3602.                                     </strong>
  3603.                                 </div>
  3604.                                 <div class=\"col-md-3\"><strong>Stok:</strong> \${data.stock.toFixed(2)} \${data.measurement}</div>
  3605.                                 <div class=\"col-md-3\"><strong>Birim:</strong> \${data.measurement}</div>
  3606.                             </div>
  3607.                         `;
  3608.                         \$('#info-details-content').html(detailsHtml);
  3609.                         return data;
  3610.                     },
  3611.                     error: function(data) {
  3612.                         \$('#info-details-content').html('<div class=\"text-danger\">Ürün maliyet bilgileri yüklenemedi.</div>');
  3613.                     }
  3614.                 });
  3615.             }
  3616.             \$(document).on('click', '.cost-popup-btn', function() {
  3617.                 const url = \$(this).data('url');
  3618.                 if (url) {
  3619.                     createPopup(url, 'cost-detail-window');
  3620.                 }
  3621.             });
  3622.             // Unallocated modal açıldığında mask'i uygula
  3623.             \$('#unallocatedModal').on('shown.bs.modal', function() {
  3624.                 applyMasks();
  3625.             });
  3626.             // Unallocated modal aç/kapat ve değerleri senkronize et
  3627.             \$(document).on('click', '#open-unallocated-modal', function() {
  3628.                 // Mevcut değerleri moda aktarma
  3629.                 const currentQty = \$('#adder-unallocated-quantity').val() || 0;
  3630.                 const currentUnit = \$('#adder-unallocated-quantity-unit-select').val() || '';
  3631.                 \$('#modal-unallocated-quantity').val(Number(currentQty).toFixed(2));
  3632.                 // Seçili ürünün saklanan birimlerini modal select'ine doldur
  3633.                 const selectedProduct = getSelectedProduct();
  3634.                 if (selectedProduct && selectedProduct.convertibleUnits) {
  3635.                     populateSelectWithUnits(\$('#modal-unallocated-unit'), selectedProduct.convertibleUnits);
  3636.                 } else {
  3637.                     \$('#modal-unallocated-unit').empty().append('<option value=\"\">-</option>');
  3638.                 }
  3639.                 \$('#modal-unallocated-unit').val(currentUnit);
  3640.                 \$('#unallocatedModal').modal('show');
  3641.             });
  3642.             // 'Tahsis Edilmemiş Miktar' Modal'ındaki Kaydet Butonunun Düzeltilmiş Hali
  3643.             \$(document).on('click', '#save-unallocated-btn', function() {
  3644.                 const uuid = \$('#unallocatedModal').data('current-uuid');
  3645.                 const qty = \$('#modal-unallocated-quantity').val() || 0;
  3646.                 const newUnallocatedQty = convertToDecimal(qty).toNumber();
  3647.                 // DURUM 1: Satış listesindeki bir satır güncelleniyor (uuid mevcut)
  3648.                 if (uuid) {
  3649.                     // 1. soldList'teki ilgili ürünü bul ve unAllocatedQuantity'yi güncelle
  3650.                     const itemIndex = soldList.findIndex(item => item.uuid === uuid);
  3651.                     if (itemIndex > -1) {
  3652.                         soldList[itemIndex].unAllocatedQuantity = newUnallocatedQty;
  3653.                     }
  3654.                     // 2. Sadece ilgili satırı ID ile hedefle ve içindeki göstergeyi güncelle
  3655.                     const \$row = \$(`#\${uuid}`);
  3656.                     \$row.find('.unalloc-display').text(newUnallocatedQty.toFixed(2));
  3657.                     // 3. Satırın genel toplamlarını ve stokları güncelle
  3658.                     updateSoldProductFromRow(uuid);
  3659.                 }
  3660.                 // DURUM 2: Adder-row (ekleme satırı) güncelleniyor (uuid mevcut değil)
  3661.                 else {
  3662.                     // Sadece adder-row'daki gizli input'u ve göstergeyi güncelle
  3663.                     \$('#adder-unallocated-quantity').val(newUnallocatedQty).trigger('change');
  3664.                     \$('#unalloc-display').text(newUnallocatedQty.toFixed(2));
  3665.                     // Adder-row'daki toplamı yeniden hesapla
  3666.                     onInputChange.call(\$('#adder-unallocated-quantity')[0]);
  3667.                 }
  3668.                 // İşlem tamamlandıktan sonra modalı kapat
  3669.                 \$('#unallocatedModal').modal('hide');
  3670.                 // Modal'daki uuid verisini temizle ki bir sonraki açılışta karışmasın
  3671.                 \$('#unallocatedModal').removeData('current-uuid');
  3672.             });
  3673.             function formatState(state) {
  3674.                 if (!state.id) {
  3675.                     return state.text;
  3676.                 }
  3677.                 var baseUrl = \"/images\";
  3678.                 var \$state = \$(
  3679.                     '<span><img src=\"' + baseUrl + '/' + state.element.dataset.image + '\" class=\"img-flag list-image\" style=\"width: 50px;\"/> ' + state.text + '</span>'
  3680.                 );
  3681.                 return \$state;
  3682.             };
  3683.             \$('#productselect').select2({
  3684.                 theme: 'bootstrap4',
  3685.                 dropdownCssClass: 'custom-select-dropdown',
  3686.                 placeholder: 'Ürün Seçin',
  3687.                 allowClear: true
  3688.             });
  3689.             function showErrorAlert(message) {
  3690.                 Swal.fire({
  3691.                     icon: 'error',
  3692.                     title: 'Oops...',
  3693.                     text: '' + message,
  3694.                     background: 'white',
  3695.                 });
  3696.             }
  3697.             window.addEventListener(\"error\", function(event) {
  3698.                 showErrorAlert(event.message);
  3699.             });
  3700.             function showSuccessAlert(message) {
  3701.                 Swal.fire({
  3702.                     icon: 'success',
  3703.                     title: 'Başarılı',
  3704.                     text: '' + message,
  3705.                     background: 'white',
  3706.                 });
  3707.             }
  3708.             \$('#submitbtn').on('click', function(event) {
  3709.                 event.preventDefault();
  3710.                 if (soldList.length === 0) {
  3711.                     showErrorAlert(\"";
  3712.         // line 3581
  3713.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("sale.errors.cannot_save_without_products", [], "messages");
  3714.         yield "\");
  3715.                     return;
  3716.                 }
  3717.                 if (!validateSalesForm()) {
  3718.                     return;
  3719.                 }
  3720.                 const saleTotalValue = convertToDecimal(getTotalSoldAmount()).toNumber();
  3721.                 const currentPaymentTotal = convertToDecimal(calculateTotalPaymentAmount()).toNumber();
  3722.                 const saleDate = getSaleDateValue();
  3723.                 if (payments.length === 0 && saleTotalValue > PAYMENT_TOLERANCE) {
  3724.                     openAutoPaymentModal({
  3725.                         scenario: 'no-payment',
  3726.                         amount: saleTotalValue,
  3727.                         saleTotal: saleTotalValue,
  3728.                         currentPayments: currentPaymentTotal,
  3729.                         saleDate: saleDate
  3730.                     });
  3731.                     return;
  3732.                 }
  3733.                 const diffValue = convertToDecimal(saleTotalValue).minus(convertToDecimal(currentPaymentTotal)).toNumber();
  3734.                 if (Math.abs(diffValue) > PAYMENT_TOLERANCE) {
  3735.                     if (diffValue < 0) {
  3736.                         showErrorAlert('Girilen ödeme tutarı satış tutarını aşıyor. Lütfen ödeme kayıtlarını kontrol edin.');
  3737.                         return;
  3738.                     }
  3739.                     openAutoPaymentModal({
  3740.                         scenario: 'mismatch',
  3741.                         amount: diffValue,
  3742.                         saleTotal: saleTotalValue,
  3743.                         currentPayments: currentPaymentTotal,
  3744.                         saleDate: saleDate
  3745.                     });
  3746.                     return;
  3747.                 }
  3748.                 submitSalesRequest();
  3749.             });
  3750.             function addCommas(number) {
  3751.                 let decimals = 2;
  3752.                 number = (number + '').replace(/[^0-9+\\-Ee.]/g, '');
  3753.                 var n = !isFinite(+number) ? 0 : +number;
  3754.                 var prec = !isFinite(+decimals) ? 0 : Math.abs(decimals);
  3755.                 var sep = ',';
  3756.                 var dec = '.';
  3757.                 var s = '';
  3758.                 var toFixedFix = function(n, prec) {
  3759.                     var k = Math.pow(10, prec);
  3760.                     return '' + (Math.round(n * k) / k).toFixed(prec);
  3761.                 };
  3762.                 s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.');
  3763.                 if (s[0].length > 3) {
  3764.                     s[0] = s[0].replace(/\\B(?=(?:\\d{3})+(?!\\d))/g, sep);
  3765.                 }
  3766.                 if ((s[1] || '').length < prec) {
  3767.                     s[1] = s[1] || '';
  3768.                     s[1] += new Array(prec - s[1].length + 1).join('0');
  3769.                 }
  3770.                 return s.join(dec);
  3771.             }
  3772.             \$(document).on('input change', '#products_sold_totalUnitPurchasePrice, #products_sold_quantity, #products_sold_unAllocatedQuantity, #products_sold_discount, #products_sold_tax', function() {
  3773.                 var purchasePrice = \$('#products_sold_totalUnitPurchasePrice').val() || \"0\";
  3774.                 var purchasePriceClean = parseFloat(purchasePrice.replace(/,/g, \"\")) || 0;
  3775.                 var cost = parseFloat(\$('#hidden-cost-input').val()) || 0;
  3776.                 var quantity = \$('#products_sold_quantity').val() || \"0\";
  3777.                 var quantityClean = parseFloat(quantity.replace(/,/g, \"\")) || 0;
  3778.                 var unAllocatedQuantity = \$('#products_sold_unAllocatedQuantity').val() || \"0\";
  3779.                 var unAllocatedQuantityClean = parseFloat(unAllocatedQuantity.replace(/,/g, \"\")) || 0;
  3780.                 var discountPercentage = \$('#products_sold_discount').val() || \"0\";
  3781.                 var discountPercentageClean = parseFloat(discountPercentage.replace(/,/g, \"\")) || 0;
  3782.                 var taxPercentage = \$('#products_sold_tax').val() || \"0\";
  3783.                 var taxPercentageClean = parseFloat(taxPercentage.replace(/,/g, \"\")) || 0;
  3784.                 var totalQuantity = quantityClean + unAllocatedQuantityClean;
  3785.                 var totalSalePriceBeforeDiscount = purchasePriceClean * totalQuantity;
  3786.                 var discountAmount = (totalSalePriceBeforeDiscount * discountPercentageClean) / 100;
  3787.                 var totalSalePriceAfterDiscount = totalSalePriceBeforeDiscount - discountAmount;
  3788.                 var taxAmount = (totalSalePriceAfterDiscount * taxPercentageClean) / 100;
  3789.                 var totalSalePrice = totalSalePriceAfterDiscount + taxAmount;
  3790.                 \$('#products_sold_totalSalePrice').val(addCommas(totalSalePrice.toFixed(2)));
  3791.                 \$('#products_sold_totalPuchasePrice').val(addCommas(totalSalePrice.toFixed(2)));
  3792.                 cost = roundToDecimal(cost);
  3793.                 var salePriceWithoutTax = totalSalePrice / (1 + taxPercentageClean / 100);
  3794.                 var totalCost = totalQuantity * cost;
  3795.                 var profit = salePriceWithoutTax - totalCost;
  3796.                 var profitSpan;
  3797.                 if (profit > 0) {
  3798.                     profitSpan = \"<span style='color:green'>\" + profit.toFixed(2).toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, \",\") + \" €</span>\";
  3799.                 } else {
  3800.                     profitSpan = \"<span style='color:red'>\" + profit.toFixed(2).toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, \",\") + \" €</span>\";
  3801.                 }
  3802.                 \$('.profit-info-span').html(profitSpan);
  3803.             });
  3804.             \$('#payment_amount').mask(\"#,##0.00\", {
  3805.                 reverse: true
  3806.             });
  3807.             // Show/Hide Voucher Code field based on Payment Method
  3808.             \$('#payment_paymentMethod').on('change', function() {
  3809.                 var selectedText = \$(this).find(\"option:selected\").text().trim().toLowerCase();
  3810.                 var \$voucherField = \$('#payment_voucherCode');
  3811.                 var \$voucherLabel = \$('label[for=\"payment_voucherCode\"]');
  3812.                 
  3813.                 if (selectedText.includes('hediye') || selectedText.includes('gift') || selectedText.includes('çek')) {
  3814.                     \$voucherField.show();
  3815.                     \$voucherLabel.show();
  3816.                     \$voucherField.attr('required', 'required');
  3817.                 } else {
  3818.                     \$voucherField.hide();
  3819.                     \$voucherLabel.hide();
  3820.                     \$voucherField.val('');
  3821.                     \$voucherField.removeAttr('required');
  3822.                 }
  3823.             });
  3824.             \$('#sales_form_customer').select2({
  3825.                 theme: 'bootstrap4',
  3826.                 dropdownCssClass: 'custom-select-dropdown',
  3827.                 placeholder: 'Müşteri Seçin',
  3828.                 allowClear: true
  3829.             });
  3830.             \$('.js-edit-customer').on('click', function() {
  3831.                 let customerId = \$('#sales_form_customer').val();
  3832.                 if (!customerId) {
  3833.                     showErrorAlert(\"";
  3834.         // line 3716
  3835.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("selectCustomerForEdit", [], "messages");
  3836.         yield "\");
  3837.                 } else {
  3838.                     \$.ajax({
  3839.                         url: '/admin/customer/detail/' + customerId,
  3840.                         type: 'GET',
  3841.                         dataType: 'json',
  3842.                         success: function(response) {
  3843.                             showUpdateModal(customerId, response);
  3844.                         },
  3845.                         error: function(jqXHR, textStatus, errorThrown) {
  3846.                             if (jqXHR.status === 404) {
  3847.                                 showErrorAlert(\"Seçilen müşteri veritabanında bulunamadı.\");
  3848.                             } else {
  3849.                                 showErrorAlert('Müşteri bilgileri yüklenirken bir hata oluştu.');
  3850.                             }
  3851.                             clearCustomerFields();
  3852.                         }
  3853.                     });
  3854.                 }
  3855.             });
  3856.             \$('#sales_form_customer').on('change', function() {
  3857.                 let customerId = \$(this).val();
  3858.                 if (!customerId) {
  3859.                     clearCustomerFields();
  3860.                     return;
  3861.                 }
  3862.                 \$.ajax({
  3863.                     url: '/admin/customer/detail/' + customerId,
  3864.                     type: 'GET',
  3865.                     dataType: 'json',
  3866.                     success: function(response) {
  3867.                         if (!response.phone || !response.email || !response.address) {
  3868.                             showUpdateModal(customerId, response);
  3869.                         } else {
  3870.                             populateCustomerFields(response);
  3871.                         }
  3872.                     },
  3873.                     error: function(jqXHR, textStatus, errorThrown) {
  3874.                         if (jqXHR.status === 404) {
  3875.                             showErrorAlert(\"Seçilen müşteri veritabanında bulunamadı.\");
  3876.                         } else {
  3877.                             showErrorAlert('Müşteri bilgileri yüklenirken bir hata oluştu.');
  3878.                         }
  3879.                         clearCustomerFields();
  3880.                     }
  3881.                 });
  3882.             });
  3883.             function populateCustomerFields(customer) {
  3884.                 \$('#update_customer_fullName').val(customer.fullName);
  3885.                 \$('#update_customer_email').val(customer.email);
  3886.                 \$('#update_customer_phone').val(customer.phone);
  3887.                 \$('#update_customer_address').val(customer.address);
  3888.             }
  3889.             function clearCustomerFields() {
  3890.                 \$('#update_customer_fullName, #update_customer_email, #update_customer_phone, #update_customer_address').val('');
  3891.             }
  3892.             function showUpdateModal(id, customer) {
  3893.                 \$('#update_customer_id').val(id);
  3894.                 \$('#update_customer_email').val(customer.email || '');
  3895.                 \$('#update_customer_phone').val(customer.phone || '');
  3896.                 \$('#update_customer_address').val(customer.address || '');
  3897.                 \$('#update_customer_fullName').val(customer.fullName || '');
  3898.                 \$('#updateCustomerModal').modal('show');
  3899.             }
  3900.             \$('#updateCustomerForm').on('submit', function(e) {
  3901.                 e.preventDefault();
  3902.                 let customerId = \$('#update_customer_id').val();
  3903.                 let formData = {
  3904.                     email: \$('#update_customer_email').val(),
  3905.                     phone: \$('#update_customer_phone').val(),
  3906.                     address: \$('#update_customer_address').val(),
  3907.                     fullName: \$('#update_customer_fullName').val()
  3908.                 };
  3909.                 \$.ajax({
  3910.                     url: '/admin/customer/update/' + customerId,
  3911.                     type: 'POST',
  3912.                     data: formData,
  3913.                     success: function(response) {
  3914.                         \$('#updateCustomerModal').modal('hide');
  3915.                         populateCustomerFields(response);
  3916.                         showSuccessAlert(\"";
  3917.         // line 3802
  3918.         echo $this->env->getExtension('Symfony\Bridge\Twig\Extension\TranslationExtension')->trans("customerUpdateSuccess", [], "messages");
  3919.         yield "\");
  3920.                     },
  3921.                     error: function(jqXHR, textStatus, errorThrown) {
  3922.                         let errorMessage = 'Güncelleme sırasında bilinmeyen bir hata oluştu.';
  3923.                         try {
  3924.                             const response = JSON.parse(jqXHR.responseText);
  3925.                             if (response && response.message) {
  3926.                                 errorMessage = response.message;
  3927.                             }
  3928.                         } catch (e) {
  3929.                             console.error(\"JSON Parse Error:\", e);
  3930.                             console.error(\"Server Response:\", jqXHR.responseText);
  3931.                         }
  3932.                         showErrorAlert(errorMessage);
  3933.                     }
  3934.                 });
  3935.             });
  3936.             \$('#show-info-btn').on('click', function(e) {
  3937.                 e.preventDefault();
  3938.                 const selectedProductId = \$('#productselect').val();
  3939.                 if (!selectedProductId || selectedProductId <= 0) {
  3940.                     showErrorAlert(\"Detayları görmek için önce bir ürün seçmelisiniz.\");
  3941.                     return;
  3942.                 }
  3943.                 const \$infoContent = \$('#info-details-content');
  3944.                 const \$icon = \$(this).find('i');
  3945.                 \$infoContent.toggle();
  3946.                 if (\$infoContent.is(':visible')) {
  3947.                     \$icon.removeClass('fa-info-circle').addClass('fa-chevron-up');
  3948.                 } else {
  3949.                     \$icon.removeClass('fa-chevron-up').addClass('fa-info-circle');
  3950.                 }
  3951.             });
  3952.             // --- GIFT VOUCHER LOGIC ---
  3953.             // Hediye Kuponu Butonuna Tıklama (Desktop)
  3954.             \$('#btn-gift-voucher').on('click', function() {
  3955.                 openGiftVoucherModal();
  3956.             });
  3957.              // Hediye Kuponu Butonuna Tıklama (Mobile)
  3958.             \$('#btn-gift-voucher-mobile').on('click', function() {
  3959.                 openGiftVoucherModal();
  3960.             });
  3961.             function openGiftVoucherModal() {
  3962.                 const customerId = \$('#sales_form_customer').val();
  3963.                 if (!customerId) {
  3964.                     showErrorAlert('Lütfen önce bir müşteri seçiniz.');
  3965.                     return;
  3966.                 }
  3967.                 // API'den bakiye sorgula
  3968.                 \$.ajax({
  3969.                     url: '/admin/gift-certificates/api/balance/' + customerId,
  3970.                     method: 'GET',
  3971.                     success: function(response) {
  3972.                         if (response.error) {
  3973.                             showErrorAlert(response.error);
  3974.                             return;
  3975.                         }
  3976.                         \$('#voucher-total-balance').text(response.formatted);
  3977.                         \$('#voucher-total-balance').data('balance', response.balance);
  3978.                         \$('#voucher-customer-name').text(response.customerName); // Set customer name
  3979.                         \$('#voucher-use-amount').val(''); // Inputu temizle
  3980.                          // Varsayılan olarak kalanı doldurmayı deneyebiliriz ama kullanıcı girişi daha iyi
  3981.                         const totals = aggregateSoldTotals();
  3982.                          const paymentTotal = convertToDecimal(calculateTotalPaymentAmount());
  3983.                         const remaining = totals.grandTotal.minus(paymentTotal);
  3984.                          if (remaining.greaterThan(0)) {
  3985.                              // Eğer kalan miktar, bakiyeden küçükse kalanı, büyükse bakiyeyi öner
  3986.                              const balance = new Decimal(response.balance);
  3987.                              const suggested = remaining.lessThan(balance) ? remaining : balance;
  3988.                              \$('#voucher-use-amount').val(suggested.toNumber());
  3989.                          }
  3990.                         \$('#gift-voucher-usage-modal').modal('show');
  3991.                     },
  3992.                     error: function() {
  3993.                         showErrorAlert('Müşteri hediye çeki bakiyesi sorgulanırken bir hata oluştu.');
  3994.                     }
  3995.                 });
  3996.             }
  3997.             // Hediye Çeki Kullanımını Onayla
  3998.             \$('#btn-confirm-voucher-usage').on('click', function() {
  3999.                 const amount = parseFloat(\$('#voucher-use-amount').val());
  4000.                 const balance = parseFloat(\$('#voucher-total-balance').data('balance'));
  4001.                 if (isNaN(amount) || amount <= 0) {
  4002.                     showErrorAlert('Lütfen geçerli bir miktar giriniz.');
  4003.                     return;
  4004.                 }
  4005.                 if (amount > balance) {
  4006.                     showErrorAlert('Girdiğiniz miktar, toplam bakiyeden fazla olamaz.');
  4007.                     return;
  4008.                 }
  4009.                 // Ödeme Yöntemini Bul (Hediye Çeki / Gift Voucher)
  4010.                 let voucherMethodId = null;
  4011.                 // 1. Yöntem: Backend'den gelen veriyi kullan (En Sağlam)
  4012.                 // 1. Yöntem: Backend'den gelen veriyi kullan (En Sağlam)
  4013.                 ";
  4014.         // line 3914
  4015.         if (array_key_exists("paymentMethods"$context)) {
  4016.             // line 3915
  4017.             yield "                    const methods = [
  4018.                         ";
  4019.             // line 3916
  4020.             $context['_parent'] = $context;
  4021.             $context['_seq'] = CoreExtension::ensureTraversable((isset($context["paymentMethods"]) || array_key_exists("paymentMethods"$context) ? $context["paymentMethods"] : (function () { throw new RuntimeError('Variable "paymentMethods" does not exist.'3916$this->source); })()));
  4022.             foreach ($context['_seq'] as $context["_key"] => $context["pm"]) {
  4023.                 // line 3917
  4024.                 yield "                            { id: \"";
  4025.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["pm"], "id", [], "any"falsefalsefalse3917), "html"nulltrue);
  4026.                 yield "\", name: \"";
  4027.                 yield $this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape($this->env->getRuntime('Twig\Runtime\EscaperRuntime')->escape(CoreExtension::getAttribute($this->env$this->source$context["pm"], "name", [], "any"falsefalsefalse3917), "js"), "html"nulltrue);
  4028.                 yield "\" },
  4029.                         ";
  4030.             }
  4031.             $_parent $context['_parent'];
  4032.             unset($context['_seq'], $context['_key'], $context['pm'], $context['_parent']);
  4033.             $context array_intersect_key($context$_parent) + $_parent;
  4034.             // line 3919
  4035.             yield "                    ];
  4036.                     const voucherMethod = methods.find(m => 
  4037.                         (m.name && m.name.toLowerCase().includes('hediye')) || 
  4038.                         (m.name && m.name.toLowerCase().includes('gift')) || 
  4039.                         (m.name && m.name.toLowerCase().includes('kupon'))
  4040.                     );
  4041.                     if (voucherMethod) {
  4042.                         voucherMethodId = voucherMethod.id;
  4043.                     }
  4044.                 ";
  4045.         }
  4046.         // line 3929
  4047.         yield "
  4048.                 // 2. Yöntem: Eğer yukarıdaki çalışmazsa DOM'dan bulmayı dene
  4049.                 if (!voucherMethodId) {
  4050.                      const \$methodSelect = \$('select[name=\"paymentMethod[]\"]').first(); // Tablodaki herhangi bir select
  4051.                      \$methodSelect.find('option').each(function() {
  4052.                         const text = \$(this).text().toLowerCase();
  4053.                         if (text.includes('hediye') || text.includes('gift') || text.includes('kupon')) {
  4054.                             voucherMethodId = \$(this).val();
  4055.                             return false; // break
  4056.                         }
  4057.                     });
  4058.                 }
  4059.                 
  4060.                 // 3. Yöntem: Modal Select
  4061.                 if (!voucherMethodId) {
  4062.                      const \$modalSelect = \$('#add-payment-modal select[name=\"paymentMethod\"]');
  4063.                      \$modalSelect.find('option').each(function() {
  4064.                         const text = \$(this).text().toLowerCase();
  4065.                         if (text.includes('hediye') || text.includes('gift') || text.includes('kupon')) {
  4066.                             voucherMethodId = \$(this).val();
  4067.                             return false; // break
  4068.                         }
  4069.                     });
  4070.                 }
  4071.                 if (!voucherMethodId) {
  4072.                      // Eğer modal select'inde yoksa, bir de manuel tanımlı ID varsa onu kontrol et (opsiyonel)
  4073.                      // Veya uyarı ver
  4074.                      // Fallback: İlk metodun id'sini alma riskine girmeyelim, kullanıcıya soralım veya hata verelim.
  4075.                      // Ancak genelde bir \"Hediye Çeki\" metodu olmalı.
  4076.                      // Şimdilik hata verelim.
  4077.                      showErrorAlert('Sistemde \"Hediye Çeki\" ödeme yöntemi bulunamadı. Lütfen yönetim panelinden ekleyiniz.');
  4078.                      return;
  4079.                 }
  4080.                 // Yeni ödeme satırı ekle
  4081.                 const payment = {
  4082.                     uuid: crypto.randomUUID(),
  4083.                     amount: amount,
  4084.                     status: \"0\", // Ödendi
  4085.                     paymentDate: new Date().toISOString().split('T')[0], // Bugün
  4086.                     paymentDueDate: new Date().toISOString().split('T')[0], // Bugün
  4087.                     paymentMethod: voucherMethodId,
  4088.                     description: 'Hediye Çeki Kullanımı',
  4089.                     voucherCode: 'AUTO_DEDUCT_FROM_BALANCE' // Backend bunu işleyip ilgili çeklerden düşebilir
  4090.                 };
  4091.                 payments.push(payment);
  4092.                 fetchPaymentForm();
  4093.                 fetchSoldListRows(); // Trigger AVOIR row update
  4094.                 \$('#gift-voucher-usage-modal').modal('hide');
  4095.                 showSuccessAlert(amount + ' TL hediye çeki ödemesi eklendi.');
  4096.             });
  4097.             // calculateTotalPaymentAmount fonksiyonunu global scope'ta bulamadıysak buraya ekleyelim veya mevcut olanı kullanalım
  4098.             function calculateTotalPaymentAmount() {
  4099.                 let total = new Decimal(0);
  4100.                 payments.forEach(function(p) {
  4101.                    total = total.plus(convertToDecimal(p.amount));
  4102.                 });
  4103.                 return total;
  4104.             }
  4105.             // --- END GIFT VOUCHER LOGIC ---
  4106.         });
  4107.         function createPopup(url, window_name = 'example-popup') {
  4108.             var width = 1100;
  4109.             var height = 700;
  4110.             var screen_width = window.screen.width;
  4111.             var screen_height = window.screen.height;
  4112.             var popup_left = (screen_width - width) / 2;
  4113.             var popup_top = (screen_height - height) / 2;
  4114.             var popup_window = window.open(url, window_name, 'width=' + width + ',height=' + height + ',left=' + popup_left + ',top=' + popup_top);
  4115.         }
  4116.     </script>
  4117. ";
  4118.         
  4119.         $__internal_6f47bbe9983af81f1e7450e9a3e3768f->leave($__internal_6f47bbe9983af81f1e7450e9a3e3768f_prof);
  4120.         
  4121.         $__internal_5a27a8ba21ca79b61932376b2fa922d2->leave($__internal_5a27a8ba21ca79b61932376b2fa922d2_prof);
  4122.         yield from [];
  4123.     }
  4124.     /**
  4125.      * @codeCoverageIgnore
  4126.      */
  4127.     public function getTemplateName(): string
  4128.     {
  4129.         return "admin/sales/index.html.twig";
  4130.     }
  4131.     /**
  4132.      * @codeCoverageIgnore
  4133.      */
  4134.     public function isTraitable(): bool
  4135.     {
  4136.         return false;
  4137.     }
  4138.     /**
  4139.      * @codeCoverageIgnore
  4140.      */
  4141.     public function getDebugInfo(): array
  4142.     {
  4143.         return array (  4528 => 3929,  4516 => 3919,  4505 => 3917,  4501 => 3916,  4498 => 3915,  4496 => 3914,  4381 => 3802,  4292 => 3716,  4154 => 3581,  3773 => 3203,  3624 => 3057,  3077 => 2513,  3073 => 2512,  3066 => 2507,  3057 => 2504,  3050 => 2503,  3046 => 2502,  3035 => 2494,  3031 => 2493,  3027 => 2492,  2590 => 2058,  2233 => 1703,  2227 => 1702,  2221 => 1700,  2218 => 1699,  2214 => 1698,  1971 => 1458,  1459 => 949,  1327 => 820,  1317 => 812,  1314 => 811,  1305 => 808,  1301 => 807,  1293 => 802,  1289 => 801,  1285 => 800,  1281 => 799,  1277 => 798,  1273 => 797,  1269 => 796,  1265 => 795,  1261 => 794,  1257 => 793,  1253 => 792,  1249 => 791,  1246 => 790,  1241 => 789,  1239 => 788,  1231 => 783,  1212 => 768,  1199 => 767,  1181 => 759,  1177 => 758,  1170 => 754,  1165 => 752,  1159 => 749,  1149 => 742,  1135 => 731,  1131 => 730,  1123 => 725,  1119 => 724,  1115 => 723,  1107 => 720,  1101 => 719,  1095 => 718,  1084 => 710,  1070 => 699,  1066 => 698,  1058 => 693,  1050 => 688,  1043 => 684,  1031 => 675,  1016 => 663,  1012 => 662,  1004 => 657,  997 => 653,  990 => 649,  983 => 645,  971 => 636,  958 => 626,  954 => 625,  948 => 622,  944 => 621,  940 => 620,  931 => 614,  918 => 604,  914 => 603,  904 => 596,  897 => 592,  887 => 585,  875 => 576,  870 => 574,  866 => 573,  860 => 570,  855 => 568,  847 => 563,  834 => 553,  798 => 520,  790 => 515,  746 => 474,  737 => 468,  724 => 458,  720 => 457,  715 => 455,  711 => 454,  707 => 453,  703 => 452,  699 => 451,  683 => 438,  676 => 434,  668 => 428,  657 => 426,  653 => 425,  649 => 424,  644 => 422,  623 => 404,  619 => 403,  615 => 402,  611 => 401,  607 => 400,  603 => 399,  594 => 392,  592 => 391,  584 => 386,  579 => 384,  574 => 382,  562 => 373,  556 => 369,  553 => 367,  547 => 363,  543 => 362,  539 => 361,  535 => 360,  528 => 356,  524 => 355,  518 => 352,  514 => 351,  506 => 347,  495 => 338,  489 => 334,  480 => 327,  474 => 323,  469 => 320,  466 => 319,  461 => 315,  459 => 312,  447 => 303,  442 => 301,  439 => 300,  437 => 299,  433 => 297,  431 => 296,  426 => 293,  424 => 292,  411 => 282,  406 => 279,  404 => 278,  399 => 275,  397 => 274,  392 => 271,  390 => 270,  384 => 266,  382 => 265,  372 => 257,  359 => 256,  104 => 10,  91 => 9,  79 => 4,  66 => 3,  43 => 1,);
  4144.     }
  4145.     public function getSourceContext(): Source
  4146.     {
  4147.         return new Source("{% extends 'base.html.twig' %}
  4148. {% block title %}
  4149.     {% trans %}
  4150.         sales
  4151.     {% endtrans %}
  4152. {% endblock %}
  4153. {% block head %}
  4154.     <style>
  4155.         /* Keep all form elements at 12px on this page */
  4156.         select, textarea, button { font-size: 12px !important; }
  4157.         .form-control, .custom-select { font-size: 12px !important; }
  4158.         /* Select2 text sizes */
  4159.         .select2-container .select2-selection__rendered,
  4160.         .select2-results__option,
  4161.         .select2-container .select2-search__field { font-size: 12px !important; }
  4162.         #adder-allocated-quantity,
  4163.         #adder-quantity-unit {
  4164.             vertical-align: middle;
  4165.         }
  4166.         .product-select-cell {
  4167.             max-width: 250px;
  4168.             /* Hücrenin alabileceği maksimum genişlik. İstediğiniz gibi ayarlayın. */
  4169.             white-space: nowrap;
  4170.             overflow: hidden;
  4171.             text-overflow: ellipsis;
  4172.         }
  4173.         /* Ekleme Satırı Stilleri */
  4174.         #adder-row {
  4175.             background-color: #f8f9fa;
  4176.             /* Hafif gri arkaplan */
  4177.         }
  4178.         #adder-row td {
  4179.             vertical-align: middle;
  4180.             padding: 0.25rem; /* Boşluk azaltıldı */
  4181.             border-top: 2px dashed #e3e6f0;
  4182.         }
  4183.         /* Adder satırında hücreler arası yatay boşluğu minimuma indir */
  4184.         #adder-row .input-group { margin-right: 4px; }
  4185.         #adder-row .btn-icon, #adder-row .btn { margin-right: 4px; }
  4186.         /* Yeni Card Header Stili */
  4187.         .bg-light-blue {
  4188.             background-color: #f0f3ff !important;
  4189.             /* Hafif mavi arkaplan */
  4190.         }
  4191.         #product-list-table-tbody input {
  4192.             /*border: none;*/
  4193.             /*padding: 0;*/
  4194.             /*margin: 0;*/
  4195.             background-color: white;
  4196.         }
  4197.         .info-span {
  4198.             color: red;
  4199.             font-weight: bold;
  4200.         }
  4201.         .cost-detail-button {
  4202.             color: blue;
  4203.             font-width: bold;
  4204.             border: none;
  4205.             background-color: transparent;
  4206.         }
  4207.         .attention-icon {
  4208.             display: inline-block;
  4209.             vertical-align: middle;
  4210.             margin-left: 5px;
  4211.             font-size: 16px;
  4212.             color: red;
  4213.             font-weight: bold;
  4214.         }
  4215.         .quantity-input-added {
  4216.             width: 60px;
  4217.         }
  4218.         .select2-container {
  4219.             width: 100% !important;
  4220.             /* Genişlik uyumluluğu için */
  4221.         }
  4222.         /* En kritik CSS düzeltmesi olmasa da, z-index çakışmalarına karşı bir güvencedir.
  4223.            Asıl çözüm JavaScript'tedir. */
  4224.         .select2-container--open {
  4225.             z-index: 1056 !important;
  4226.         }
  4227.         .select2-container {
  4228.             width: 100% !important;
  4229.         }
  4230.         .select2-container--open {
  4231.             z-index: 1056 !important;
  4232.         }
  4233.         .select2-container--bootstrap4 .select2-selection--single
  4234.         {
  4235.             padding: .50rem !important;
  4236.         }
  4237.         .select2-container .select2-selection--single {
  4238.             height: 28px !important;
  4239.         }
  4240.         /* === SEÇİM KARTLARI İÇİN CSS === */
  4241.         .selection-card-label {
  4242.             display: block;
  4243.             cursor: pointer;
  4244.             width: 100%;
  4245.         }
  4246.         .selection-card {
  4247.             border: 2px solid #e3e6f0;
  4248.             border-radius: 0.5rem;
  4249.             padding: 0.50rem;
  4250.             transition: all 0.2s ease-in-out;
  4251.             display: flex;
  4252.             justify-content: center;
  4253.             align-items: center;
  4254.             width: 100%;
  4255.         }
  4256.         /* Kartın üzerine gelindiğinde (hover) */
  4257.         .selection-card:hover {
  4258.             border-color: #4e73df;
  4259.             transform: translateY(-2px);
  4260.             /* Hafif yukarı kalkma efekti */
  4261.             box-shadow: 0 4px 10px rgba(0, 0, 0, 0.05);
  4262.         }
  4263.         /* Kart içindeki başlık (Fatura, Proforma) */
  4264.         .selection-title {
  4265.             font-size: 1.1rem;
  4266.             font-weight: 500;
  4267.             color: #5a5c69;
  4268.             transition: color 0.2s ease-in-out;
  4269.         }
  4270.         /* Onay işareti (başlangıçta gizli) */
  4271.         .checkmark {
  4272.             font-size: 1.25rem;
  4273.             color: #4e73df;
  4274.             opacity: 0;
  4275.             transform: scale(0.5);
  4276.             transition: all 0.2s ease-out;
  4277.             margin-left: 0.75rem;
  4278.         }
  4279.         /* SEÇİM YAPILDIĞINDAKİ STİLLER */
  4280.         /* CSS :has() seçicisi ile, içindeki radio input seçili olan etiketin kartını stillendiriyoruz. */
  4281.         .selection-card-label:has(input[type=\"radio\"]:checked) .selection-card {
  4282.             border-color: #4e73df;
  4283.             background-color: #f0f3ff;
  4284.         }
  4285.         /* Seçili kartın başlık rengini değiştir */
  4286.         .selection-card-label:has(input[type=\"radio\"]:checked) .selection-title {
  4287.             color: #4e73df;
  4288.             font-weight: 600;
  4289.         }
  4290.         /* Seçili kartın onay işaretini görünür yap */
  4291.         .selection-card-label:has(input[type=\"radio\"]:checked) .checkmark {
  4292.             opacity: 1;
  4293.             transform: scale(1);
  4294.         }
  4295.         /* Bilgi satırı için stil */
  4296.         #info-details-content {
  4297.             background-color: #f1faff;
  4298.             /* Hafif mavi arka plan */
  4299.             border-bottom: 2px dashed #e3e6f0;
  4300.             /* Altına kesikli çizgi ekler */
  4301.         }
  4302.         .info-details-content-class {
  4303.             background-color: #f1faff;
  4304.             /* Hafif mavi arka plan */
  4305.             border-bottom: 2px dashed #e3e6f0;
  4306.             /* Altına kesikli çizgi ekler */
  4307.         }
  4308.         /* Make product table full-width and remove right gaps */
  4309.         .card-body > .table-responsive { padding-right: 0; }
  4310.         #product-list-table { width: 100% !important; table-layout: fixed; }
  4311.         #product-list-table th, #product-list-table td { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  4312.         #product-list-table .product-select-cell select { width: 100%; }
  4313.         /* Adjust specific column widths to fit viewport */
  4314.         .summary-row td {
  4315.             border-top: none;
  4316.             background-color: #f8f9fc;
  4317.             padding: 0;
  4318.         }
  4319.         .sale-summary-row {
  4320.             display: flex;
  4321.             justify-content: flex-end;
  4322.             align-items: center;
  4323.             gap: 12px;
  4324.             padding: 0.35rem 0.75rem;
  4325.             border-radius: 0.35rem;
  4326.             margin-right: 1.5rem;
  4327.         }
  4328.         .sale-summary-row .summary-label {
  4329.             font-weight: 600;
  4330.             color: #4b5563;
  4331.             white-space: nowrap;
  4332.         }
  4333.         .sale-summary-row .summary-value {
  4334.             font-weight: 700;
  4335.             color: #111827;
  4336.             text-align: right;
  4337.             min-width: 120px;
  4338.             white-space: nowrap;
  4339.         }
  4340.         .sale-summary-row.summary-tax .summary-label,
  4341.         .sale-summary-row.summary-tax .summary-value {
  4342.             display: flex;
  4343.             flex-direction: column;
  4344.             align-items: flex-end;
  4345.             gap: 4px;
  4346.         }
  4347.         .sale-summary-row.summary-tax .summary-label div,
  4348.         .sale-summary-row.summary-tax .summary-value div {
  4349.             white-space: nowrap;
  4350.         }
  4351.         .sale-summary-row.summary-total .summary-value {
  4352.             font-size: 1.25rem;
  4353.         }
  4354.         #product-list-table th:nth-child(1), #product-list-table td:nth-child(1) { width: 5%; }
  4355.         #product-list-table th:nth-child(2), #product-list-table td:nth-child(2) { width: 25%; }
  4356.         #product-list-table th:nth-child(3), #product-list-table td:nth-child(3) { width: 10%; }
  4357.         #product-list-table th:nth-child(4), #product-list-table td:nth-child(4) { width: 10%; }
  4358.         #product-list-table th:nth-child(5), #product-list-table td:nth-child(5) { width: 10%; }
  4359.         #product-list-table th:nth-child(6), #product-list-table td:nth-child(6) { width: 8%; }
  4360.         #product-list-table th:nth-child(7), #product-list-table td:nth-child(7) { width: 8%; }
  4361.         #product-list-table th:nth-child(8), #product-list-table td:nth-child(8) { width: 15%; }
  4362.         #product-list-table th:nth-child(9), #product-list-table td:nth-child(9) { width: 9%; }
  4363.     </style>
  4364. {% endblock %}
  4365. {% block body %}
  4366.     <div class=\"container-fluid m-0 p-0\">
  4367.         <div class=\"card shadow mb-4\">
  4368.             <div class=\"card-header py-3 d-flex justify-content-between align-items-center\">
  4369.                 <div class=\"btn-group\" role=\"group\">
  4370.                     <div class=\"d-md-none\">
  4371.                         <div class=\"dropdown\">
  4372.                             <button class=\"btn btn-secondary dropdown-toggle\" type=\"button\" id=\"dropdownMenuButton\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\">
  4373.                                 {% trans %} actions {% endtrans %}
  4374.                             </button>
  4375.                             <div class=\"dropdown-menu\" aria-labelledby=\"dropdownMenuButton\">
  4376.                                 <button type=\"button\" class=\"dropdown-item\" data-toggle=\"modal\" data-target=\"#payments-modal\">
  4377.                                     <i class=\"fas fa-money-check-alt mr-1\"></i>
  4378.                                     {% trans %}payments{% endtrans %}
  4379.                                 </button>
  4380.                                 <button type=\"button\" data-toggle=\"modal\" data-target=\"#add-customer-modal\" class=\"dropdown-item\">
  4381.                                     <i class=\"fas fa-user-plus mr-1\"></i>
  4382.                                     {% trans %}addCustomer{% endtrans %}
  4383.                                 </button>
  4384.                                 <button type=\"button\" class=\"dropdown-item js-edit-customer\">
  4385.                                     <i class=\"fas fa-user-edit mr-1\"></i>
  4386.                                     {% trans %}editCustomer{% endtrans %}
  4387.                                 </button>
  4388.                                 <button type=\"button\" class=\"dropdown-item\" id=\"btn-gift-voucher-mobile\">
  4389.                                     <i class=\"fas fa-gift mr-1\"></i>
  4390.                                     {{ 'giftVoucher'|trans }}
  4391.                                 </button>
  4392.                             </div>
  4393.                         </div>
  4394.                     </div>
  4395.                     <div class=\"d-none d-md-block\">
  4396.                         <div class=\"btn-group\" role=\"group\">
  4397.                             <button type=\"button\" class=\"btn btn-outline-secondary\" data-toggle=\"modal\" data-target=\"#payments-modal\">
  4398.                                 <i class=\"fas fa-money-check-alt mr-1\"></i>
  4399.                                 {% trans %}payments{% endtrans %}
  4400.                             </button>
  4401.                             <button type=\"button\" data-toggle=\"modal\" data-target=\"#add-customer-modal\" class=\"btn btn-outline-secondary\">
  4402.                                 <i class=\"fas fa-user-plus mr-1\"></i>
  4403.                                 {% trans %}addCustomer{% endtrans %}
  4404.                             </button>
  4405.                             <button type=\"button\" class=\"btn btn-outline-secondary js-edit-customer\">
  4406.                                 {% trans %}editCustomer{% endtrans %}
  4407.                             </button>
  4408.                             <button type=\"button\" class=\"btn btn-outline-secondary\" id=\"btn-gift-voucher\" title=\"{{ 'useGiftVoucher'|trans }}\">
  4409.                                 <i class=\"fas fa-gift mr-1\"></i>
  4410.                                 {{ 'giftVoucher'|trans }}
  4411.                             </button>
  4412.                         </div>
  4413.                     </div>
  4414.                 </div>
  4415.                 <button type=\"button\" id=\"submitbtn\" class=\"btn btn-success\">
  4416.                     <i class=\"fas fa-save mr-1\"></i>
  4417.                     {% trans %}
  4418.                         save
  4419.                     {% endtrans %}
  4420.                 </button>
  4421.             </div>
  4422.             <div class=\"card-body\">
  4423.                 {# FATURA VE PROFORMA SEÇENEKLERİ #}
  4424.                 <div class=\"form-group\">
  4425.                     <label class=\"form-label font-weight-bold\">{{ 'salesType'|trans }}</label>
  4426.                     <div class=\"row\">
  4427.                         {# Fatura Seçeneği #}
  4428.                         <div class=\"col-md-6\">
  4429.                             <label class=\"selection-card-label\">
  4430.                                 <input type=\"radio\" name=\"salesType\" class=\"d-none\" value=\"invoice\">
  4431.                                 <div class=\"selection-card\">
  4432.                                     <span class=\"selection-title\">{% trans %}invoice{% endtrans %}</span>
  4433.                                     <i class=\"fas fa-check-circle checkmark\"></i>
  4434.                                 </div>
  4435.                             </label>
  4436.                         </div>
  4437.                         {# Proforma Seçeneği #}
  4438.                         <div class=\"col-md-6\">
  4439.                             <label class=\"selection-card-label\">
  4440.                                 <input type=\"radio\" name=\"salesType\" class=\"d-none\" value=\"proforma\" checked>
  4441.                                 <div class=\"selection-card\">
  4442.                                     <span class=\"selection-title\">{% trans %}proforma{% endtrans %}</span>
  4443.                                     <i class=\"fas fa-check-circle checkmark\"></i>
  4444.                                 </div>
  4445.                             </label>
  4446.                         </div>
  4447.                     </div>
  4448.                 </div>
  4449.                 <div style=\"margin-bottom: 10px\">
  4450.                     {# SATIŞ FORMU başlangıç #}
  4451.                     {{ form_start(form) }}
  4452.                     <div class=\"\">
  4453.                         <div class=\"row\">
  4454.                             <div class=\"col-lg-6 col-md-12\">
  4455.                                 {{ form_row(form.totalPurchasePrice) }}
  4456.                                 {{ form_row(form.status) }}
  4457.                             </div>
  4458.                             <div class=\"col-lg-6 col-md-12\">
  4459.                                 {{ form_row(form.customer) }}
  4460.                                 {{ form_row(form.seller) }}
  4461.                             </div>
  4462.                         </div>
  4463.                         <div class=\"row\">
  4464.                             <div class=\"col-lg-3 col-md-6\">{{ form_row(form.salesDate) }}</div>
  4465.                             <div class=\"col-lg-3 col-md-6\">{{ form_row(form.deliveryDate) }}</div>
  4466.                             <div class=\"col-lg-3 col-md-6\">{{ form_row(form.dueDate) }}</div>
  4467.                             <div class=\"col-lg-3 col-md-6\">{{ form_row(form.validDate) }}</div>
  4468.                         </div>
  4469.                     </div>
  4470.                     {# SATIŞ FORMU bitiş #}
  4471.                     {# Ödemeler Tablosu modal #}
  4472.                     <div class=\"modal fade\" id=\"payments-modal\" role=\"dialog\" aria-labelledby=\"paymentsModalLabel\" aria-hidden=\"true\">
  4473.                         <div class=\"modal-dialog modal-xl\" role=\"document\">
  4474.                             <div class=\"modal-content\">
  4475.                                 <div class=\"modal-header\">
  4476.                                     <h5 class=\"modal-title\" id=\"paymentsModalLabel\">{% trans %}payments{% endtrans %}</h5>
  4477.                                     <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\">
  4478.                                         <span aria-hidden=\"true\">&times;</span>
  4479.                                     </button>
  4480.                                 </div>
  4481.                                 <div class=\"modal-body\">
  4482.                                     <div class=\"card mb-1\">
  4483.                                         <div class=\"card-header d-flex align-items-center justify-content-between\">
  4484.                                             <div>
  4485.                                                 <h5 class=\"mb-0\">{% trans %}payments{% endtrans %}</h5>
  4486.                                                 <div style=\"float: left; width: 250px\">
  4487.                                                     {% trans %}total{% endtrans %}:
  4488.                                                     <span id=\"total-amount-span\"></span>
  4489.                                                     {% trans %}remainingAmount{% endtrans %}:
  4490.                                                     <span id=\"remainder-amount-span\"></span>
  4491.                                                 </div>
  4492.                                             </div>
  4493.                                             <button class=\"btn btn-primary\" type=\"button\" id=\"btn-addPayment\" data-toggle=\"modal\" data-target=\"#add-payment-modal\">
  4494.                                                 {% trans %}addPayment{% endtrans %}
  4495.                                             </button>
  4496.                                         </div>
  4497.                                         <div class=\"card-body\">
  4498.                                             <div>
  4499.                                                 <table class=\"table\" id=\"payment-list-table\">
  4500.                                                     <thead>
  4501.                                                     <tr>
  4502.                                                         <th>{% trans %}amount{% endtrans %}</th>
  4503.                                                         <th>{% trans %}status{% endtrans %}</th>
  4504.                                                         <th>{% trans %}paymentDate{% endtrans %}</th>
  4505.                                                         <th>{% trans %}dueDate{% endtrans %}</th>
  4506.                                                         <th>{% trans %}paymentMethod{% endtrans %}</th>
  4507.                                                         <th>{% trans %}description{% endtrans %}</th>
  4508.                                                         <th>&nbsp;</th>
  4509.                                                     </tr>
  4510.                                                     </thead>
  4511.                                                     <tbody id=\"payment-list-table-tbody\"></tbody>
  4512.                                                 </table>
  4513.                                             </div>
  4514.                                         </div>
  4515.                                     </div>
  4516.                                 </div>
  4517.                             </div>
  4518.                         </div>
  4519.                     </div>
  4520.                     <div class=\"card border-0 shadow-sm\">
  4521.                         <div class=\"card-header bg-light-blue border-0 py-3\">
  4522.                             <div class=\"row align-items-center\">
  4523.                                 <div class=\"col-md-4\">
  4524.                                     <label for=\"warehouse-select\" class=\"font-weight-bold mb-1\">{% trans %}warehouse{% endtrans %}</label>
  4525.                                     <select id=\"warehouseselect\" class=\"form-control\">
  4526.                                         <option value=\"\">{% trans %}selectwarehouse{% endtrans %}</option>
  4527.                                         {% for warehouse in warehouses %}
  4528.                                             <option value=\"{{ warehouse.id }}\">{{ warehouse.name }}</option>
  4529.                                         {% endfor %}
  4530.                                     </select>
  4531.                                 </div>
  4532.                                 <div class=\"col-md-5\"></div>
  4533.                                 <div id=\"product-info-box\" class=\"col-md-3\" style=\"display: none;\">
  4534.                                     <div class=\"info-box-content\">
  4535.                                         <div>
  4536.                                             {% trans %}stockQuantity{% endtrans %}:
  4537.                                             <strong id=\"info-stock\"></strong>
  4538.                                         </div>
  4539.                                         <div>
  4540.                                             {% trans %}averageCost{% endtrans %}:
  4541.                                             <strong id=\"info-cost\"></strong>
  4542.                                         </div>
  4543.                                     </div>
  4544.                                 </div>
  4545.                             </div>
  4546.                         </div>
  4547.                         <div class=\"card-body\" style=\"padding: 0\">
  4548.                             <div class=\"table-responsive\">
  4549.                                 <table class=\"table modern-table\" id=\"product-list-table\" style=\"width: 100%;\">
  4550.                                     <thead>
  4551.                                     <tr>
  4552.                                         <th style=\"width: 5%;\">{% trans %}info{% endtrans %}</th>
  4553.                                         <th style=\"width: 20%;\">{% trans %}product{% endtrans %}</th>
  4554.                                         <th style=\"width: 20%;\">{% trans %}quantity{% endtrans %}</th>
  4555.                                         <th style=\"width: 15%;\">{% trans %}unitPrice{% endtrans %}</th>
  4556.                                         <th style=\"width: 10%;\">{% trans %}discount{% endtrans %} (%)</th>
  4557.                                         <th style=\"width: 10%;\">TVA (%)</th>
  4558.                                         <th style=\"width: 15%; text-align: left !important;\" class=\"text-right\">{% trans %}total{% endtrans %}</th>
  4559.                                         <th style=\"width: 15%;\" class=\"text-center\">{% trans %}action{% endtrans %}</th>
  4560.                                     </tr>
  4561.                                     </thead>
  4562.                                     <tbody id=\"product-list-table-tbody\">
  4563.                                     </tbody>
  4564.                                     <tbody id=\"adder-body\">
  4565.                                     <tr id=\"adder-row\">
  4566.                                         <td>
  4567.                                             <button type=\"button\" id=\"show-info-btn\"
  4568.                                                     class=\"btn btn-sm btn-info btn-icon\" title=\"{{ 'productInfo'|trans }}\">
  4569.                                                 <i class=\"fas fa-info-circle\"></i>
  4570.                                             </button>
  4571.                                         </td>
  4572.                                         <td class=\"product-select-cell\">
  4573.                                             <select id=\"productselect\" class=\"form form-control\">
  4574.                                                 <option value=\"\">{{ 'selectWarehouseFirst'|trans }}</option>
  4575.                                             </select>
  4576.                                         </td>
  4577.                                         <td>
  4578.                                             <div class=\"input-group input-group-sm\" style=\"max-width: 220px;\">
  4579.                                                 <input type=\"text\" id=\"adder-allocated-quantity\" class=\"form-control\" value=\"0\" min=\"0\">
  4580.                                                 <div class=\"input-group-append\">
  4581.                                                     <select id=\"adder-quantity-unit-select\" class=\"custom-select custom-select-sm\">
  4582.                                                         <option value=\"\">-</option>
  4583.                                                     </select>
  4584.                                                 </div>
  4585.                                             </div>
  4586.                                         </td>
  4587.                                         <td><input type=\"text\" id=\"adder-price\" value=\"0\" min=\"0\"
  4588.                                                    class=\"form-control form-control-sm price-mask\" placeholder=\"Fiyat\">
  4589.                                         </td>
  4590.                                         <td>
  4591.                                             <select name=\"adder-discount-select\" id=\"adder-discount-select\"
  4592.                                                     class=\"form-control form-control-sm\">
  4593.                                                 <option value=\"0\">% 0</option>
  4594.                                                 <option value=\"1\">% 1</option>
  4595.                                                 <option value=\"2\">% 2</option>
  4596.                                                 <option value=\"3\">% 3</option>
  4597.                                                 <option value=\"4\">% 4</option>
  4598.                                                 <option value=\"5\">% 5</option>
  4599.                                                 <option value=\"20\">% 20</option>
  4600.                                                 <option value=\"30\">% 30</option>
  4601.                                                 <option value=\"100\">% 100</option>
  4602.                                             </select>
  4603.                                         </td>
  4604.                                         <td>
  4605.                                             <select name=\"adder-tva-select\" id=\"adder-tva-select\"
  4606.                                                     class=\"form-control form-control-sm\">
  4607.                                                 <option value=\"0\" disabled>% 0</option>
  4608.                                                 <option value=\"10\">% 10</option>
  4609.                                                 <option value=\"20\">% 20</option>
  4610.                                             </select>
  4611.                                         </td>
  4612.                                         <td class=\"text-right font-weight-bold small\">
  4613.                                             <input name=\"adder-total\" id=\"adder-total\" type=\"number\"
  4614.                                                    class=\"form-control form-control-sm\"
  4615.                                                    placeholder=\"{% trans %} total {% endtrans %}\"/>
  4616.                                         </td>
  4617.                                         <td class=\"text-center\">
  4618.                                             <div class=\"btn-group\" role=\"group\">
  4619.                                                 <button type=\"button\" id=\"open-unallocated-modal\" class=\"btn btn-outline-secondary btn-sm\" title=\"{% trans %}unAllocatedQuantity{% endtrans %}\">
  4620.                                                     <i class=\"fas fa-box-open\"></i>
  4621.                                                     <span id=\"unalloc-display\" class=\"badge badge-light ml-1\">0</span>
  4622.                                                 </button>
  4623.                                                 <button type=\"button\" id=\"add-product-row-btn\"
  4624.                                                         class=\"btn btn-sm btn-success btn-icon\">
  4625.                                                     <i class=\"fas fa-plus\"></i>
  4626.                                                 </button>
  4627.                                             </div>
  4628.                                             <input type=\"number\" id=\"adder-unallocated-quantity\" class=\"form-control d-none\" value=\"0\" min=\"0\">
  4629.                                             <select id=\"adder-unallocated-quantity-unit-select\" class=\"custom-select custom-select-sm d-none\">
  4630.                                                 <option value=\"\">-</option>
  4631.                                             </select>
  4632.                                         </td>
  4633.                                     </tr>
  4634.                                     <tr id=\"info-details-row\">
  4635.                                         <td colspan=\"8\" style=\"padding: 0; border-top: none;\">
  4636.                                             <div id=\"info-details-content\" class=\"p-3\" style=\"display: none;\">
  4637.                                             </div>
  4638.                                         </td>
  4639.                                     </tr>
  4640.                                     </tbody>
  4641.                                     <tfoot>
  4642.                                         <!-- Rows will be injected by updateTotalAmounts() -->
  4643.                                         <tr class=\"summary-row-placeholder\">
  4644.                                             <td colspan=\"8\"></td>
  4645.                                         </tr>
  4646.                                     </tfoot>
  4647.                                 </table>
  4648.                             </div>
  4649.                         </div>
  4650.                     </div>
  4651.                     {{ form_end(form) }}
  4652.                 </div>
  4653.             </div>
  4654.         </div>
  4655.     </div>
  4656.     <div class=\"modal fade\" id=\"add-customer-modal\" role=\"dialog\" aria-labelledby=\"customerModalLabel\" aria-hidden=\"true\">
  4657.         <div class=\"modal-dialog\" role=\"document\">
  4658.             <div class=\"modal-content\">
  4659.                 <div class=\"modal-header\">
  4660.                     <h5 class=\"modal-title\" id=\"customerModalLabel\">{% trans %}addCustomer{% endtrans %}</h5>
  4661.                     <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\">
  4662.                         <span aria-hidden=\"true\">&times;</span>
  4663.                     </button>
  4664.                 </div>
  4665.                 {{ form_start(customerForm) }}
  4666.                 <div class=\"modal-body\">
  4667.                     {{ form_widget(customerForm) }}
  4668.                 </div>
  4669.                 <div class=\"modal-footer\">
  4670.                     <button type=\"button\" class=\"btn btn-secondary\" data-dismiss=\"modal\">{% trans %}cancel{% endtrans %}</button>
  4671.                     <button type=\"submit\" id=\"btn-customer-save\" class=\"btn btn-primary\">{% trans %}save{% endtrans %}</button>
  4672.                 </div>
  4673.                 {{ form_end(customerForm) }}
  4674.             </div>
  4675.         </div>
  4676.     </div>
  4677.     <div class=\"modal fade\" id=\"unallocatedModal\" tabindex=\"-1\" role=\"dialog\" aria-labelledby=\"unallocatedModalLabel\" aria-hidden=\"true\">
  4678.         <div class=\"modal-dialog\" role=\"document\">
  4679.             <div class=\"modal-content\">
  4680.                 <div class=\"modal-header\">
  4681.                     <h5 class=\"modal-title\" id=\"unallocatedModalLabel\">{% trans %}unAllocatedQuantity{% endtrans %}</h5>
  4682.                     <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\">
  4683.                         <span aria-hidden=\"true\">&times;</span>
  4684.                     </button>
  4685.                 </div>
  4686.                 <div class=\"modal-body\">
  4687.                     <div class=\"form-group\">
  4688.                         <label for=\"modal-unallocated-quantity\">{% trans %}quantity{% endtrans %}</label>
  4689.                         <input type=\"text\" id=\"modal-unallocated-quantity\" class=\"form-control mask-money\" value=\"0\">
  4690.                     </div>
  4691.                     <div class=\"form-group\">
  4692.                         <label for=\"modal-unallocated-unit\">{% trans %}unit{% endtrans %}</label>
  4693.                         <select id=\"modal-unallocated-unit\" class=\"custom-select\">
  4694.                             <option value=\"\">-</option>
  4695.                         </select>
  4696.                     </div>
  4697.                 </div>
  4698.                 <div class=\"modal-footer\">
  4699.                     <button type=\"button\" class=\"btn btn-secondary\" data-dismiss=\"modal\">{% trans %}close{% endtrans %}</button>
  4700.                     <button type=\"button\" id=\"save-unallocated-btn\" class=\"btn btn-primary\">{% trans %}save{% endtrans %}</button>
  4701.                 </div>
  4702.             </div>
  4703.         </div>
  4704.     </div>
  4705.     <div class=\"modal fade\" id=\"add-payment-modal\" role=\"dialog\" aria-labelledby=\"paymentModalLabel\" aria-hidden=\"true\">
  4706.         <div class=\"modal-dialog\" role=\"document\">
  4707.             <div class=\"modal-content\">
  4708.                 <div class=\"modal-header\">
  4709.                     <h5 class=\"modal-title\" id=\"paymentModalLabel\">{% trans %}addPayment{% endtrans %}</h5>
  4710.                     <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\">
  4711.                         <span aria-hidden=\"true\">&times;</span>
  4712.                     </button>
  4713.                 </div>
  4714.                 <div class=\"modal-body\">
  4715.                     {{ form_widget(paymentForm) }}
  4716.                     {{ form_start(paymentForm) }}
  4717.                     {{ form_end(paymentForm) }}
  4718.                 </div>
  4719.                 <div class=\"modal-footer\">
  4720.                     <button type=\"button\" class=\"btn btn-secondary\" data-dismiss=\"modal\">{% trans %}cancel{% endtrans %}</button>
  4721.                     <button type=\"button\" id=\"save-payment-btn\" class=\"btn btn-primary\">{% trans %}save{% endtrans %}</button>
  4722.                 </div>
  4723.             </div>
  4724.         </div>
  4725.     </div>
  4726.     <div class=\"modal fade\" id=\"updateCustomerModal\" tabindex=\"-1\" role=\"dialog\" aria-labelledby=\"updateModalLabel\" aria-hidden=\"true\">
  4727.         <div class=\"modal-dialog\" role=\"document\">
  4728.             <div class=\"modal-content\">
  4729.                 <div class=\"modal-header\">
  4730.                     <h5 class=\"modal-title\" id=\"updateModalLabel\">{% trans %}updateCustomerInfoMessage{% endtrans %}</h5>
  4731.                     <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\">
  4732.                         <span aria-hidden=\"true\">&times;</span>
  4733.                     </button>
  4734.                 </div>
  4735.                 <form id=\"updateCustomerForm\">
  4736.                     <div class=\"modal-body\">
  4737.                         <input type=\"hidden\" id=\"update_customer_id\">
  4738.                         <div class=\"form-group\">
  4739.                             <label for=\"update_customer_fullName\">{% trans %}fullName{% endtrans %}</label>
  4740.                             <input type=\"text\" class=\"form-control\" id=\"update_customer_fullName\" required>
  4741.                         </div>
  4742.                         <div class=\"form-group\">
  4743.                             <label for=\"update_customer_email\">{% trans %}email{% endtrans %}</label>
  4744.                             <input type=\"email\" class=\"form-control\" id=\"update_customer_email\">
  4745.                         </div>
  4746.                         <div class=\"form-group\">
  4747.                             <label for=\"update_customer_phone\">{% trans %}phone{% endtrans %}</label>
  4748.                             <input type=\"text\" class=\"form-control\" id=\"update_customer_phone\">
  4749.                         </div>
  4750.                         <div class=\"form-group\">
  4751.                             <label for=\"update_customer_address\">{% trans %}address{% endtrans %}</label>
  4752.                             <textarea class=\"form-control\" id=\"update_customer_address\" rows=\"3\"></textarea>
  4753.                         </div>
  4754.                     </div>
  4755.                     <div class=\"modal-footer\">
  4756.                         <button type=\"button\" class=\"btn btn-secondary\" data-dismiss=\"modal\">{% trans %}close{% endtrans %}</button>
  4757.                         <button type=\"submit\" class=\"btn btn-primary\">{% trans %}save{% endtrans %}</button>
  4758.                     </div>
  4759.                 </form>
  4760.             </div>
  4761.         </div>
  4762.     </div>
  4763.     <div class=\"modal fade\" id=\"updateServiceModal\" tabindex=\"-1\" role=\"dialog\" aria-labelledby=\"updateServiceModalLabel\" aria-hidden=\"true\">
  4764.         <div class=\"modal-dialog\" role=\"document\">
  4765.             <div class=\"modal-content\">
  4766.                 <div class=\"modal-header\">
  4767.                     <h5 class=\"modal-title\" id=\"updateServiceModalLabel\">{% trans %}updateServiceInfoMessage{% endtrans %}</h5>
  4768.                     <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\">
  4769.                         <span aria-hidden=\"true\">&times;</span>
  4770.                     </button>
  4771.                 </div>
  4772.                 <form id=\"updateServiceForm\" onsubmit=\"return false;\">
  4773.                     <div class=\"modal-body\">
  4774.                         <input type=\"hidden\" id=\"update_service_id\">
  4775.                         <div class=\"form-group\">
  4776.                             <label for=\"update_service_name\">{% trans %}serviceName{% endtrans %}</label>
  4777.                             <input type=\"text\" class=\"form-control\" id=\"update_service_name\">
  4778.                         </div>
  4779.                         <div class=\"form-group\">
  4780.                             <label for=\"update_service_cost\">{% trans %}cost{% endtrans %}</label>
  4781.                             <input type=\"text\" value=\"0.00\" class=\"form-control mask-money\" id=\"update_service_cost\" required>
  4782.                         </div>
  4783.                         <div class=\"form-group\">
  4784.                             <label for=\"update_service_description\">{% trans %}description{% endtrans %}</label>
  4785.                             <input type=\"text\" class=\"form-control\" id=\"update_service_description\">
  4786.                         </div>
  4787.                     </div>
  4788.                     <div class=\"modal-footer\">
  4789.                         <button type=\"button\" class=\"btn btn-secondary\" data-dismiss=\"modal\">{% trans %}close{% endtrans %}</button>
  4790.                         <button type=\"button\" class=\"btn btn-primary\" id=\"service_modal_save_changes_btn\">{% trans %}save{% endtrans %}</button>
  4791.                     </div>
  4792.                 </form>
  4793.             </div>
  4794.         </div>
  4795.     </div>
  4796.     <div class=\"modal fade\" id=\"autoPaymentModal\" tabindex=\"-1\" role=\"dialog\" aria-labelledby=\"autoPaymentModalLabel\" aria-hidden=\"true\">
  4797.         <div class=\"modal-dialog modal-dialog-centered\" role=\"document\">
  4798.             <div class=\"modal-content\">
  4799.                 <div class=\"modal-header\">
  4800.                     <h5 class=\"modal-title\" id=\"autoPaymentModalLabel\">{{ 'autoPaymentConfirmation'|trans }}</h5>
  4801.                     <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\">
  4802.                         <span aria-hidden=\"true\">&times;</span>
  4803.                     </button>
  4804.                 </div>
  4805.                 <div class=\"modal-body\">
  4806.                     <p id=\"auto-payment-message\" class=\"mb-3\"></p>
  4807.                     <div class=\"border rounded px-3 py-2 bg-light\">
  4808.                         <div class=\"d-flex justify-content-between\"><span>{{ 'salesTotal'|trans }}</span><span id=\"auto-payment-sale-total\">0,00 {{ 'currency.symbol'|trans }}</span></div>
  4809.                         <div class=\"d-flex justify-content-between\"><span>{{ 'currentPayments'|trans }}</span><span id=\"auto-payment-current-payments\">0,00 {{ 'currency.symbol'|trans }}</span></div>
  4810.                         <div class=\"d-flex justify-content-between font-weight-bold\"><span>{{ 'paymentToAdd'|trans }}</span><span id=\"auto-payment-amount\">0,00 {{ 'currency.symbol'|trans }}</span></div>
  4811.                         <hr>
  4812.                         <div class=\"small\">
  4813.                             <div><strong>{{ 'paymentStatusLabel'|trans }}:</strong> <span id=\"auto-payment-status\"></span></div>
  4814.                             <div><strong>{{ 'paymentTypeLabel'|trans }}:</strong> <span id=\"auto-payment-method\"></span></div>
  4815.                             <div><strong>{{ 'description'|trans }}:</strong> <span id=\"auto-payment-description\"></span></div>
  4816.                         </div>
  4817.                     </div>
  4818.                 </div>
  4819.                 <div class=\"modal-footer\">
  4820.                     <button type=\"button\" class=\"btn btn-secondary\" data-dismiss=\"modal\">{{ 'cancel'|trans }}</button>
  4821.                     <button type=\"button\" class=\"btn btn-primary\" id=\"confirm-auto-payment\">{{ 'confirmAction'|trans }}</button>
  4822.                 </div>
  4823.             </div>
  4824.         </div>
  4825.     </div>
  4826.     <!-- Hediye Çeki Kullanım Modalı -->
  4827.     <div class=\"modal fade\" id=\"gift-voucher-usage-modal\" tabindex=\"-1\" role=\"dialog\" aria-labelledby=\"giftVoucherUsageModalLabel\" aria-hidden=\"true\">
  4828.         <div class=\"modal-dialog modal-dialog-centered\" role=\"document\">
  4829.             <div class=\"modal-content\">
  4830.                 <div class=\"modal-header\">
  4831.                     <h5 class=\"modal-title\" id=\"giftVoucherUsageModalLabel\">{{ 'giftVoucherUsage'|trans }}</h5>
  4832.                     <button type=\"button\" class=\"close\" data-dismiss=\"modal\" aria-label=\"Close\">
  4833.                         <span aria-hidden=\"true\">&times;</span>
  4834.                     </button>
  4835.                 </div>
  4836.                 <div class=\"modal-body\">
  4837.                     <div class=\"alert alert-info\">
  4838.                         <strong><span id=\"voucher-customer-name\"></span></strong>{{ 'voucherBalanceInfoSuffix'|trans }}: <strong id=\"voucher-total-balance\">0.00 TL</strong>
  4839.                     </div>
  4840.                     <div class=\"form-group\">
  4841.                         <label for=\"voucher-use-amount\">{{ 'amountToUse'|trans }}</label>
  4842.                         <input type=\"number\" id=\"voucher-use-amount\" class=\"form-control\" placeholder=\"0.00\" min=\"0\" step=\"0.01\">
  4843.                         <small class=\"form-text text-muted\">{{ 'enterAmountToUse'|trans }}</small>
  4844.                     </div>
  4845.                 </div>
  4846.                 <div class=\"modal-footer\">
  4847.                     <button type=\"button\" class=\"btn btn-secondary\" data-dismiss=\"modal\">{{ 'cancel'|trans }}</button>
  4848.                     <button type=\"button\" class=\"btn btn-primary\" id=\"btn-confirm-voucher-usage\">{{ 'confirmAndAdd'|trans }}</button>
  4849.                 </div>
  4850.             </div>
  4851.         </div>
  4852.     </div>
  4853. {% endblock %}
  4854. {% block javascript %}
  4855. <script src=\"{{ asset('/decimal.js') }}\"></script>
  4856.     <script>
  4857.         document.addEventListener('DOMContentLoaded', () => {
  4858.             const saleDateInput = document.getElementById('sales_form_salesDate');
  4859.             if (saleDateInput && !saleDateInput.value) {
  4860.                 const now = new Date();
  4861.                 const localDate = new Date(now.getTime() - now.getTimezoneOffset() * 60000).toISOString().split('T')[0];
  4862.                 saleDateInput.value = localDate;
  4863.                 saleDateInput.dispatchEvent(new Event('change', { bubbles: true }));
  4864.             }
  4865.         });
  4866.         \$(document).ready(function() {
  4867.             applyMasks();
  4868.             const isDuplicatedProforma = {{ sales is defined and sales.id is not null ? 'true' : 'false' }};
  4869.             const duplicatedSoldItems = (function(){
  4870.                 if(!isDuplicatedProforma){ return []; }
  4871.                 const items = [];
  4872.                 {% if sales is defined and sales.productsSolds is defined %}
  4873.                     {% for ps in sales.productsSolds %}
  4874.                         items.push({
  4875.                             productid: {{ ps.product ? ps.product.id : 0 }},
  4876.                             productName: '{{ ps.productName|default(ps.product ? ps.product.name : '')|e('js') }}',
  4877.                             code: '{{ ps.product ? ps.product.code|e('js') : '' }}',
  4878.                             measurement: '{{ ps.measurement is not null ? ps.measurement|e('js') : (ps.product and ps.product.measurement ? ps.product.measurement.name|e('js') : '') }}',
  4879.                             quantity: {{ ps.quantity is not null ? ps.quantity|number_format(2, '.', '') : '0' }},
  4880.                             unAllocatedQuantity: {{ ps.unAllocatedQuantity is not null ? ps.unAllocatedQuantity|number_format(2, '.', '') : '0' }},
  4881.                             unitPrice: {{ ps.totalUnitPurchasePrice is not null ? ps.totalUnitPurchasePrice|number_format(2, '.', '') : '0' }},
  4882.                             tax: {{ ps.tax is not null ? ps.tax|number_format(2, '.', '') : '0' }},
  4883.                             discount: {{ ps.discount is not null ? ps.discount|number_format(2, '.', '') : '0' }},
  4884.                             totalPurchasePrice: {{ ps.totalPuchasePrice is not null ? ps.totalPuchasePrice|number_format(2, '.', '') : (ps.totalPuchasePrice is not null ? ps.totalPuchasePrice|number_format(2, '.', '') : (ps.totalPrice is not null ? ps.totalPrice|number_format(2, '.', '') : '0')) }},
  4885.                             totalPrice: {{ ps.totalPrice }},
  4886.                             warehouse: {{ sales.warehouse ? sales.warehouse.id : 0 }},
  4887.                             thickness: 0,
  4888.                             width: 0,
  4889.                             height: 0,
  4890.                             cost: 0,
  4891.                             productType: '{{ ps.product and ps.product.productTypeEnum ? ps.product.productTypeEnum.name|e('js') : '' }}',
  4892.                             selectedUnitId: {{ ps.selectedUnit ? ps.selectedUnit.id : 'null' }}
  4893.                         });
  4894.                     {% endfor %}
  4895.                 {% endif %}
  4896.                 return items;
  4897.             })();
  4898.             // TODO: Duplicated items
  4899.             async function importDuplicatedSoldItemsIfNeeded(){
  4900.                 await getProductsFromWarehouse();
  4901.                 if(!isDuplicatedProforma || duplicatedSoldItems.length === 0){
  4902.                     return;
  4903.                 }
  4904.                 const targetWarehouseId = {{ sales is defined and sales.warehouse ? sales.warehouse.id : 0 }};
  4905.                 if(targetWarehouseId){
  4906.                     \$('#warehouseselect').val(String(targetWarehouseId));
  4907.                     \$('#warehouseselect').trigger('change');
  4908.                 }
  4909.                 const start = Date.now();
  4910.                 const timeoutMs = 15000;
  4911.                 const timer = setInterval(function(){
  4912.                     if(Array.isArray(products) && products.length > 0){
  4913.                         clearInterval(timer);
  4914.                         try{
  4915.                             duplicatedSoldItems.forEach(function(item){
  4916.                                 const p = products.find(function(prod){ return prod.productid === item.productid; });
  4917.                                 if(p){
  4918.                                     selectProduct(p.productid);
  4919.                                 }
  4920.                                 addProductToSoldList(
  4921.                                     item.productid,
  4922.                                     item.productName,
  4923.                                     item.code,
  4924.                                     item.measurement,
  4925.                                     item.quantity,
  4926.                                     item.unitPrice,
  4927.                                     item.tax,
  4928.                                     item.discount,
  4929.                                     item.totalPurchasePrice,
  4930.                                     item.warehouse,
  4931.                                     item.unAllocatedQuantity,
  4932.                                     item.thickness,
  4933.                                     item.width,
  4934.                                     item.height,
  4935.                                     item.cost,
  4936.                                     item.productType,
  4937.                                     item.selectedUnitId
  4938.                                 );
  4939.                             });
  4940.                             fetchSoldListRows();
  4941.                             updateTotalAmounts();
  4942.                             \$('#sales_form_totalPurchasePrice').val(addCommas(getTotalSoldAmount()));
  4943.                             fetchPaymentForm();
  4944.                             fetchStocks();
  4945.                         }catch(e){
  4946.                             console.error('Duplicate import error', e);
  4947.                         }
  4948.                     }else if(Date.now() - start > timeoutMs){
  4949.                         clearInterval(timer);
  4950.                         console.warn('Timed out waiting for products to load');
  4951.                     }
  4952.                 }, 200);
  4953.             }
  4954.             if(isDuplicatedProforma){
  4955.                 importDuplicatedSoldItemsIfNeeded();
  4956.             }
  4957.             // =============================================================================
  4958.             // INITIALIZATION & GLOBAL VARIABLES
  4959.             // =============================================================================
  4960.             // Collapse sidebar only on this page
  4961.             \$('body').addClass('sidebar-toggled');
  4962.             \$('#accordionSidebar').addClass('toggled');
  4963.             // Product data structure
  4964.             let product = {
  4965.                 code: \"\",
  4966.                 id: 0,
  4967.                 length: 0,
  4968.                 measurement: \"\",
  4969.                 name: \"\",
  4970.                 priceFob: 0,
  4971.                 priceNavlun: 0,
  4972.                 productid: 0,
  4973.                 purchaseTotalAmount: 0,
  4974.                 quantity: 0,
  4975.                 thickness: 0,
  4976.                 totalQuantity: 0,
  4977.                 totalUnitPrice: 0,
  4978.                 width: 0,
  4979.                 cost: 0,
  4980.                 measurementUnit: \"\",
  4981.                 stock: 0,
  4982.                 warehouseid: 0,
  4983.                 selected: false,
  4984.             }
  4985.             let products = [];
  4986.             // Sold product data structure
  4987.             let soldProduct = {
  4988.                 productid: 0,
  4989.                 productName: \"\",
  4990.                 code: \"\",
  4991.                 measurement: \"\",
  4992.                 quantity: 0,
  4993.                 baseUnitQuantity: 0,
  4994.                 unAllocatedQuantity: 0,
  4995.                 unitPrice: 0,
  4996.                 tax: 0,
  4997.                 discount: 0,
  4998.                 totalPurchasePrice: 0,
  4999.                 warehouse: 0,
  5000.             }
  5001.             let soldList = [];
  5002.             const MONEY_ROUNDING_MODE = Decimal.ROUND_HALF_UP;
  5003.             // Payment data structure
  5004.             let payment = {
  5005.                 uuid: 0,
  5006.                 id: 0,
  5007.                 amount: 0,
  5008.                 status: 0,
  5009.                 paymentDate: new Date(),
  5010.                 paymentDueDate: new Date(),
  5011.                 paymentMethod: 0,
  5012.                 description: 0,
  5013.             }
  5014.             let payments = []
  5015.             // =============================================================================
  5016.             // UTILITY FUNCTIONS
  5017.             // =============================================================================
  5018.             
  5019.              function formatCurrency(amount) {
  5020.                 if (amount instanceof Decimal) {
  5021.                     amount = amount.toNumber();
  5022.                 }
  5023.                 return addCommas(amount.toFixed(2)) + ' {{ 'currency.symbol'|trans }}';
  5024.             }
  5025.             // Convert entered quantity in selected unit to product base unit quantity
  5026.             function computeBaseUnitQuantity(productId, selectedUnitId, quantity, onDone){
  5027.                 try{
  5028.                     const product = products.find(p => p.productid === productId);
  5029.                     if(!product){ onDone(quantity); return; }
  5030.                     // If unit not selected or already base unit, fallback to same quantity
  5031.                     if(!selectedUnitId || String(selectedUnitId) === '' || String(selectedUnitId) === String(product.measurementUnitId)){
  5032.                         onDone(quantity);
  5033.                         return;
  5034.                     }
  5035.                     \$.ajax({
  5036.                         url: '/admin/measurement/convert-to-product-unit',
  5037.                         method: 'POST',
  5038.                         dataType: 'json',
  5039.                         data: {
  5040.                             productId: productId,
  5041.                             fromUnitId: selectedUnitId,
  5042.                             quantity: quantity
  5043.                         },
  5044.                         success: function(resp){
  5045.                             if(resp && resp.success){
  5046.                                 onDone(parseFloat(resp.result));
  5047.                             } else {
  5048.                                 onDone(quantity);
  5049.                             }
  5050.                         },
  5051.                         error: function(){ onDone(quantity); }
  5052.                     });
  5053.                 }catch(e){ onDone(quantity); }
  5054.             }
  5055.             // Check if product already exists in sold list with same parameters
  5056.             function issetInSoldList(productid, quantity, unitPrice, tax, discount, totalPurchasePrice) {
  5057.                 const foundProduct = soldList.find(product =>
  5058.                     product.productid === productid &&
  5059.                     product.quantity === quantity &&
  5060.                     product.unitPrice === unitPrice &&
  5061.                     product.tax === tax &&
  5062.                     product.discount === discount &&
  5063.                     product.totalPurchasePrice === totalPurchasePrice
  5064.                 );
  5065.                 return !!foundProduct;
  5066.             }
  5067.             function applyMasks() {
  5068.                 \$('.mask-money').mask(\"##0.00\", { reverse: true });
  5069.             }
  5070.             // Convert various input types to Decimal for precise calculations
  5071.             function convertToDecimal(value) {
  5072.                 try {
  5073.                     if (value instanceof Decimal) {
  5074.                         return value;
  5075.                     }
  5076.                     if (value === undefined || value === null) {
  5077.                         return new Decimal(0);
  5078.                     }
  5079.                     if (typeof value === 'number') {
  5080.                         if (!isFinite(value) || isNaN(value)) {
  5081.                             return new Decimal(0);
  5082.                         }
  5083.                         return new Decimal(value);
  5084.                     }
  5085.                     if (typeof value === 'string') {
  5086.                         var sanitized = value.replace(/[^0-9.,-]/g, '').replace(/,/g, '').trim();
  5087.                         if (sanitized === '' || sanitized === '-' || sanitized === '.' || sanitized === '-.') {
  5088.                             return new Decimal(0);
  5089.                         }
  5090.                         return new Decimal(sanitized);
  5091.                     }
  5092.                     return new Decimal(0);
  5093.                 } catch (e) {
  5094.                     return new Decimal(0);
  5095.                 }
  5096.             }
  5097.             // Round value to specified decimal places (default 2)
  5098.             function roundToDecimal(value, decimalPlaces = 2) {
  5099.                 const decimalValue = new Decimal(value);
  5100.                 const roundedValue = decimalValue.toDecimalPlaces(decimalPlaces, Decimal.ROUND_UP);
  5101.                 return roundedValue.toNumber();
  5102.             }
  5103.             // Round stock values down to prevent overselling
  5104.             function roundStockToDecimal(value, decimalPlaces = 2) {
  5105.                 const decimalValue = new Decimal(value);
  5106.                 const roundedValue = decimalValue.toDecimalPlaces(decimalPlaces, Decimal.ROUND_DOWN);
  5107.                 return roundedValue.toNumber();
  5108.             }
  5109.             // Round to nearest cent for currency calculations
  5110.             function roundToNearestCent(amount) {
  5111.                 return Math.round(amount * 100) / 100;
  5112.             }
  5113.             // Round to two decimal places
  5114.             function roundToTwoDecimals(number) {
  5115.                 var factor = Math.pow(10, 2);
  5116.                 return (Math.round(number * factor) / factor).toFixed(2);
  5117.             }
  5118.             // Validate numeric input
  5119.             function validate(s) {
  5120.                 var rgx = /^[0-9]*\\.?[0-9]*\$/;
  5121.                 return s.match(rgx);
  5122.             }
  5123.             // Convert string to float, handling commas
  5124.             function convertToFloat(value) {
  5125.                 if (typeof value === \"string\") {
  5126.                     value = value.replace(',', '');
  5127.                 }
  5128.                 return parseFloat(value);
  5129.             }
  5130.             // Add thousand separators to numbers
  5131.             function addCommas(number) {
  5132.                 let decimals = 2;
  5133.                 number = (number + '').replace(/[^0-9+\\-Ee.]/g, '');
  5134.                 var n = !isFinite(+number) ? 0 : +number;
  5135.                 var prec = !isFinite(+decimals) ? 0 : Math.abs(decimals);
  5136.                 var sep = ',';
  5137.                 var dec = '.';
  5138.                 var s = '';
  5139.                 var toFixedFix = function(n, prec) {
  5140.                     var k = Math.pow(10, prec);
  5141.                     return '' + (Math.round(n * k) / k).toFixed(prec);
  5142.                 };
  5143.                 s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.');
  5144.                 if (s[0].length > 3) {
  5145.                     s[0] = s[0].replace(/\\B(?=(?:\\d{3})+(?!\\d))/g, sep);
  5146.                 }
  5147.                 if ((s[1] || '').length < prec) {
  5148.                     s[1] = s[1] || '';
  5149.                     s[1] += new Array(prec - s[1].length + 1).join('0');
  5150.                 }
  5151.                 return s.join(dec);
  5152.             }
  5153.             // Create popup window with specified dimensions
  5154.             function createPopup(url, window_name = 'example-popup') {
  5155.                 var width = 1100;
  5156.                 var height = 700;
  5157.                 var screen_width = window.screen.width;
  5158.                 var screen_height = window.screen.height;
  5159.                 var popup_left = (screen_width - width) / 2;
  5160.                 var popup_top = (screen_height - height) / 2;
  5161.                 var popup_window = window.open(url, window_name, 'width=' + width + ',height=' + height + ',left=' + popup_left + ',top=' + popup_top);
  5162.             }
  5163.             // Show error alert using SweetAlert
  5164.             function showErrorAlert(message) {
  5165.                 Swal.fire({
  5166.                     icon: 'error',
  5167.                     title: 'Oops...',
  5168.                     text: '' + message,
  5169.                     background: 'white',
  5170.                 });
  5171.             }
  5172.             // Show success alert using SweetAlert
  5173.             function showSuccessAlert(message) {
  5174.                 Swal.fire({
  5175.                     icon: 'success',
  5176.                     title: 'Başarılı',
  5177.                     text: '' + message,
  5178.                     background: 'white',
  5179.                 });
  5180.             }
  5181.             // =============================================================================
  5182.             // PRODUCT MANAGEMENT FUNCTIONS
  5183.             // =============================================================================
  5184.             // Add product to sold list with validation
  5185.             function addProductToSoldList(
  5186.                 productid,
  5187.                 productName,
  5188.                 code,
  5189.                 measurement,
  5190.                 quantity,
  5191.                 unitPrice,
  5192.                 tax,
  5193.                 discount,
  5194.                 totalPurchasePrice,
  5195.                 warehouseid,
  5196.                 unAllocatedQuantity,
  5197.                 thickness,
  5198.                 width,
  5199.                 height,
  5200.                 cost,
  5201.                 productType,
  5202.                 selectedUnitId = null
  5203.                 ) {
  5204.                 var newQuantity = convertToDecimal(quantity).toNumber();
  5205.                 var newUnAllocatedQuantity = convertToDecimal(unAllocatedQuantity).toNumber();
  5206.                 var newPrice = convertToDecimal(unitPrice).toNumber();
  5207.                 var newTax = convertToDecimal(tax).toNumber();
  5208.                 var newDiscount = convertToDecimal(discount).toNumber();
  5209.                 var newTotalPurchasePrice = convertToDecimal(totalPurchasePrice).toNumber();
  5210.                 if (!issetInSoldList(productid, newQuantity, newPrice, newTax, newDiscount, newTotalPurchasePrice)) {
  5211.                     let productSold = {
  5212.                         uuid: crypto.randomUUID(),
  5213.                         productid: productid,
  5214.                         productName: productName,
  5215.                         code: code,
  5216.                         measurement: measurement,
  5217.                         quantity: newQuantity,
  5218.                         baseUnitQuantity: newQuantity,
  5219.                         unAllocatedQuantity: newUnAllocatedQuantity,
  5220.                         unitPrice: newPrice,
  5221.                         tax: newTax,
  5222.                         discount: newDiscount,
  5223.                         totalPurchasePrice: newTotalPurchasePrice,
  5224.                         warehouse: warehouseid,
  5225.                         thickness: thickness,
  5226.                         width: width,
  5227.                         height: height,
  5228.                         cost: cost,
  5229.                         productType: productType,
  5230.                         selectedUnitId: selectedUnitId,
  5231.                     }
  5232.                     soldList.push(productSold);
  5233.                     // compute base unit quantity asynchronously and update the item
  5234.                     computeBaseUnitQuantity(productid, selectedUnitId, newQuantity, function(baseQty){
  5235.                         const item = soldList.find(i => i.uuid === productSold.uuid);
  5236.                         if(item){ item.baseUnitQuantity = convertToDecimal(baseQty || newQuantity).toNumber(); }
  5237.                     });
  5238.                     fetchStocks();
  5239.                     fetchSoldListRows();
  5240.                     fetchPaymentForm();
  5241.                     \$('#sales_form_totalPurchasePrice').val(addCommas(getTotalSoldAmount()));
  5242.                     return productSold;
  5243.                 } else {
  5244.                     console.log(\"List + \")
  5245.                     console.log(soldList)
  5246.                     throw new Error(\"Ürün zaten listede mevcut !\")
  5247.                 }
  5248.             }
  5249.             // Remove product from sold list by UUID
  5250.             function deleteProductInSoldList(uuid) {
  5251.                 soldList = soldList.filter(product =>
  5252.                     product.uuid !== uuid
  5253.                 );
  5254.                 fetchSoldListRows();
  5255.             }
  5256.             // Mark product as selected and unselect others
  5257.             function selectProduct(productId) {
  5258.                 products.forEach(product => product.selected = false);
  5259.                 let product = products.find(product => product.productid === productId);
  5260.                 if (product) {
  5261.                     product.selected = true;
  5262.                 }
  5263.                 return products;
  5264.             }
  5265.             // Get currently selected product
  5266.             function getSelectedProduct() {
  5267.                 return products.find(product => product.selected === true);
  5268.             }
  5269.             // Update product dropdown with available products
  5270.             function updateProductSelect() {
  5271.                 \$('#productselect').empty();
  5272.                 \$('#productselect').append('<option value=\"0\" data-image=\"image-not-found.webp\">Ürün Seçin</option>');
  5273.                 \$.each(products, function(index, value) {
  5274.                     var image = value.image;
  5275.                     var option = '<option value=\"' + value.id + '\" data-image=\"' + image + '\" class=\"stockoption\">' + value.name + ' - ' + value.code + ' - ' + value.measurement + ' - ' + value.quantity + '</option>';
  5276.                     \$('#productselect').append(option);
  5277.                 });
  5278.                 \$('#productselect').attr('disabled', false);
  5279.             }
  5280.             // Load products from selected warehouse
  5281.             function getProductsFromWarehouse() {
  5282.                 var id = \$('#warehouseselect option:selected').val();
  5283.                 if (!id) {
  5284.                     return;
  5285.                 }
  5286.                 \$.ajax({
  5287.                     url: \"/warehouse-stocks/\" + id,
  5288.                     dataType: 'JSON',
  5289.                     method: 'GET',
  5290.                     success: function(response) {
  5291.                         if (response.length > 0) {
  5292.                             if (soldList.length <= 0) {
  5293.                                 products = [];
  5294.                                 \$.each(response, function(index, product) {
  5295.                                     let productObj = {
  5296.                                         code: product.code,
  5297.                                         id: product.id,
  5298.                                         image: product.image,
  5299.                                         length: 0,
  5300.                                         measurement: product.measurement,
  5301.                                         name: product.name,
  5302.                                         priceFob: 0,
  5303.                                         priceNavlun: 0,
  5304.                                         productid: product.productid,
  5305.                                         purchaseTotalAmount: 0,
  5306.                                         quantity: product.totalQuantity,
  5307.                                         unAllocatedQuantity: 0,
  5308.                                         thickness: 0,
  5309.                                         totalQuantity: product.totalQuantity,
  5310.                                         totalUnitPrice: 0,
  5311.                                         width: 0,
  5312.                                         cost: 0,
  5313.                                         measurementUnit: product.measurementUnit,
  5314.                                         measurementUnitId: product.measurementUnitId,
  5315.                                         stock: 0,
  5316.                                         warehouseid: \$('#warehouseselect option:selected').val(),
  5317.                                         convertibleUnits: [],
  5318.                                         productType: product.productTypeEnum,
  5319.                                     };
  5320.                                     products.push(productObj);
  5321.                                 });
  5322.                                 updateProductSelect();
  5323.                             }
  5324.                         } else {
  5325.                             showErrorAlert('Seçmiş olduğunuz depoda hiç ürün stoğu bulunmamaktadır.');
  5326.                         }
  5327.                     },
  5328.                     error: function(error) {
  5329.                         showErrorAlert('Bilinmeyen bir sistem hatası oluştu lütfen tekrar deneyin.');
  5330.                     }
  5331.                 });
  5332.             }
  5333.             // Update stock quantities based on sold items
  5334.             function fetchStocks() {
  5335.                 // const groupedSoldList = soldList.reduce((acc, soldProduct) => {
  5336.                 //     if (!acc[soldProduct.productid]) {
  5337.                 //         acc[soldProduct.productid] = 0;
  5338.                 //     }
  5339.                 //     acc[soldProduct.productid] += convertToDecimal(soldProduct.quantity).toNumber();
  5340.                 //     return acc;
  5341.                 // }, {});
  5342.                 const groupedSoldList = soldList.reduce((acc, soldProduct) => {
  5343.                     const serviceTypes = [\"INSTALLATION_SERVICE\", \"MAINTENANCE_SERVICE\", \"CONSULTATION_SERVICE\", \"TREE\"];
  5344.                     const productTypeKey = soldProduct.productType ? (soldProduct.productType.key || soldProduct.productType.name) : null;
  5345.                     const isService = productTypeKey ? serviceTypes.includes(productTypeKey) : false;
  5346.                     if (isService) {
  5347.                         return acc;
  5348.                     }
  5349.                     if (!acc[soldProduct.productid]) {
  5350.                         acc[soldProduct.productid] = 0;
  5351.                     }
  5352.                     const quantityToDeduct = soldProduct.baseUnitQuantity || soldProduct.quantity;
  5353.                     acc[soldProduct.productid] += convertToDecimal(quantityToDeduct).toNumber();
  5354.                     return acc;
  5355.                 }, {});
  5356.                 products.forEach(product => {
  5357.                     if (groupedSoldList[product.productid]) {
  5358.                         const totalSoldQuantity = groupedSoldList[product.productid];
  5359.                         product.quantity = roundStockToDecimal(convertToDecimal(product.totalQuantity - totalSoldQuantity).toNumber());
  5360.                     } else {
  5361.                         product.quantity = roundStockToDecimal(convertToDecimal(product.totalQuantity).toNumber());
  5362.                     }
  5363.                 });
  5364.                 calculateAndWriteDiffBetweenPaymentAndSolds();
  5365.             }
  5366.             // Validate stock quantity before adding to sold list
  5367.             // function checkStockQuantity(quantity) {
  5368.             //     let product = products.find(p => p.productid === parseInt(productId, 10));
  5369.             //     const productType = product.productType.key;
  5370.             //     if(productType === \"INSTALLATION_SERVICE\" || productType === \"MAINTENANCE_SERVICE\" || productType === \"CONSULTATION_SERVICE\" || productType === 'TREE'){
  5371.             //
  5372.             //         \$('#updateServiceModal').modal('show');
  5373.             //
  5374.             //     }else{
  5375.             //      if (convertToFloat(quantity) > product.quantity) {
  5376.             //         throw new Error('Yetersiz stok. Ekeleyebileceğiniz maksimum stok: ' + product.quantity);
  5377.             //         resetAddProductForm();
  5378.             //      }
  5379.             //     }
  5380.             //
  5381.             // }
  5382.             function checkStockQuantity() {
  5383.                 return new Promise((resolve, reject) => {
  5384.                     const selectedProduct = getSelectedProduct();
  5385.                     if (!selectedProduct) {
  5386.                         return reject(new Error('Lütfen bir ürün seçin.'));
  5387.                     }
  5388.                     const productType = selectedProduct.productType.key;
  5389.                     const isService = [\"INSTALLATION_SERVICE\", \"MAINTENANCE_SERVICE\", \"CONSULTATION_SERVICE\", \"TREE\"].includes(productType);
  5390.                     if (isService) {
  5391.                         // Eğer ürün bir hizmet ise, stok kontrolü yapma, işlemi onayla.
  5392.                         return resolve();
  5393.                     }
  5394.                     const quantityStr = \$('#adder-allocated-quantity').val();
  5395.                     const fromUnitId = \$('#adder-quantity-unit-select').val();
  5396.                     const requestedQuantity = convertToDecimal(quantityStr).toNumber();
  5397.                     // Eğer birim seçilmemişse veya miktar 0 ise, miktar kadarını stokla karşılaştır.
  5398.                     if (!fromUnitId || fromUnitId === '') {
  5399.                         if (requestedQuantity > selectedProduct.quantity) {
  5400.                             return reject(new Error(`Yetersiz stok. Eklenebilecek maksimum miktar: \${selectedProduct.quantity} \${selectedProduct.measurementUnit}`));
  5401.                         }
  5402.                         return resolve(requestedQuantity); // Temel birimdeki miktarı döndür
  5403.                     }
  5404.                     // Seçilen birimdeki miktarı, ürünün temel birimine çevir.
  5405.                     \$.ajax({
  5406.                         url: '/admin/measurement/convert-to-product-unit',
  5407.                         method: 'POST',
  5408.                         dataType: 'json',
  5409.                         data: {
  5410.                             productId: selectedProduct.productid,
  5411.                             fromUnitId: fromUnitId,
  5412.                             quantity: requestedQuantity
  5413.                         },
  5414.                         success: function(resp) {
  5415.                             if (resp && resp.success) {
  5416.                                 const requestedBaseQuantity = convertToDecimal(resp.result).toNumber();
  5417.                                 // Temel birimdeki talep edilen miktar, stoktan büyük mü diye kontrol et.
  5418.                                 if (requestedBaseQuantity > selectedProduct.quantity) {
  5419.                                     reject(new Error(`Yetersiz stok. Talep edilen miktar (\${quantityStr} \${\$('#adder-quantity-unit-select option:selected').text()}), stoktaki \${selectedProduct.quantity} \${selectedProduct.measurementUnit}'den fazla.`));
  5420.                                 } else {
  5421.                                     resolve(requestedBaseQuantity); // Kontrol başarılı, temel birimdeki miktarı döndür.
  5422.                                 }
  5423.                             } else {
  5424.                                 reject(new Error('Birim dönüştürme sırasında bir hata oluştu. Stok kontrol edilemedi.'));
  5425.                             }
  5426.                         },
  5427.                         error: function() {
  5428.                             reject(new Error('Stok kontrolü sırasında sunucuya ulaşılamadı.'));
  5429.                         }
  5430.                     });
  5431.                 });
  5432.             }
  5433.             // Get product cost information from server
  5434.             function getProductCost(pid) {
  5435.                 const url = '/product-cost/' + pid + '/' + getSelectedProduct().warehouseid;
  5436.                 \$.ajax({
  5437.                     url: \"/product-cost-detail/\" + pid + '?warehouse=' + getSelectedProduct().warehouseid,
  5438.                     method: \"POST\",
  5439.                     dataType: \"JSON\",
  5440.                     success: function(data) {
  5441.                         var product = getSelectedProduct();
  5442.                         product.cost = data.cost;
  5443.                         product.measurementUnit = data.measurement;
  5444.                         \$('.stock-info-span').html(data.stock.toFixed(2).toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, \",\") + \" \" + data.measurement);
  5445.                         \$('.cost-info-span').html(data.cost.toFixed(2).toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, \",\") + \" €\");
  5446.                         \$('.measurement-unit-info-span').html(data.measurement);
  5447.                         \$('#hidden-cost-input').val(data.cost);
  5448.                         const detailsHtml = `
  5449.                             <div class=\"row align-items-center\">
  5450.                                 <div class=\"col-md-3\">\${product.name}</div>
  5451.                                 <div class=\"col-md-3\">
  5452.                                     <strong>
  5453.                                         <button type=\"button\" class=\"btn btn-link btn-sm p-0 cost-popup-btn\" data-url=\"\${url}\">Maliyet: \${data.cost.toFixed(2)} €</button>
  5454.                                     </strong>
  5455.                                 </div>
  5456.                                 <div class=\"col-md-3\"><strong>Stok:</strong> \${data.stock.toFixed(2)} \${data.measurement}</div>
  5457.                                 <div class=\"col-md-3\"><strong>Birim:</strong> \${data.measurement}</div>
  5458.                             </div>
  5459.                         `;
  5460.                         \$('#info-details-content').html(detailsHtml);
  5461.                         return data;
  5462.                     },
  5463.                     error: function(data) {
  5464.                         \$('#info-details-content').html('<div class=\"text-danger\">Ürün maliyet bilgileri yüklenemedi.</div>');
  5465.                     }
  5466.                 });
  5467.             }
  5468.             // Generate HTML for a product row (Standard or AVOIR)
  5469.             function generateProductRowHtml(value, options = {}) {
  5470.                 const isAvoir = options.isAvoir || false;
  5471.                 const readonly = isAvoir ? 'readonly disabled' : '';
  5472.                 const inputReadonly = isAvoir ? 'readonly' : ''; // For inputs we might want just readonly, not disabled
  5473.                 const rowClass = isAvoir ? 'bg-light text-danger' : '';
  5474.                 const uuid = value.uuid;
  5475.                 // Render Service Button (only for standard rows)
  5476.                 const serviceBtnHtml = !isAvoir ? renderServiceEditBtn(value) : '';
  5477.                 
  5478.                 // Actions
  5479.                 let actionButtonsHtml = '';
  5480.                 if (!isAvoir) {
  5481.                     actionButtonsHtml = `
  5482.                         <div class=\"btn-group\" role=\"group\">
  5483.                             \${serviceBtnHtml}
  5484.                             <button type=\"button\" class=\"btn btn-outline-secondary btn-sm open-unallocated-modal-row\"
  5485.                                     data-uuid=\"\${uuid}\" title=\"{% trans %}unAllocatedQuantity{% endtrans %}\">
  5486.                                 <i class=\"fas fa-box-open\"></i>
  5487.                                 <span class=\"badge badge-light ml-1 unalloc-display\">\${value.unAllocatedQuantity.toFixed(2)}</span>
  5488.                             </button>
  5489.                             <button type=\"button\" class=\"btn btn-danger btn-sm delete-row-button\"
  5490.                                     data-uuid=\"\${uuid}\" title=\"Sil\">
  5491.                                 <i class=\"fas fa-trash\"></i>
  5492.                             </button>
  5493.                         </div>
  5494.                     `;
  5495.                 } else {
  5496.                      // Empty for AVOIR
  5497.                      actionButtonsHtml = '';
  5498.                 }
  5499.                 // Info Button
  5500.                 let infoButtonHtml = '';
  5501.                 if (!isAvoir) {
  5502.                      infoButtonHtml = `
  5503.                         <button type=\"button\" class=\"btn btn-sm btn-info btn-icon show-row-info-btn\"
  5504.                                 data-uuid=\"\${uuid}\" title=\"Ürün Bilgileri\">
  5505.                             <i class=\"fas fa-info-circle\"></i>
  5506.                         </button>
  5507.                      `;
  5508.                 }
  5509.                 // Product Select / Name
  5510.                 let productSelectHtml = '';
  5511.                 if (isAvoir) {
  5512.                     // For AVOIR, we just show a static input or disabled select mimicking the look
  5513.                     productSelectHtml = `
  5514.                         <input type=\"text\" class=\"form-control text-danger font-weight-bold\" value=\"AVOIR\" readonly>
  5515.                     `;
  5516.                 } else {
  5517.                      let productOptions = '';
  5518.                      const serviceTypes = ['INSTALLATION_SERVICE','MAINTENANCE_SERVICE','CONSULTATION_SERVICE','TREE'];
  5519.                      const isServiceRow = (function(pt){
  5520.                         try {
  5521.                             if (!pt) return false;
  5522.                             if (typeof pt === 'string') return serviceTypes.includes(pt);
  5523.                             const key = pt.key || pt.name;
  5524.                             return serviceTypes.includes(key);
  5525.                         } catch(e) { return false; }
  5526.                      })(value.productType);
  5527.                      products.forEach(function(product) {
  5528.                         const isSelected = product.productid === value.productid ? 'selected' : '';
  5529.                         const displayName = (isSelected && isServiceRow && value.productName) ? value.productName : product.name;
  5530.                         productOptions += `<option value=\"\${product.productid}\" \${isSelected}>\${displayName} - \${product.measurement} - \${product.quantity} - \${product.code}</option>`;
  5531.                      });
  5532.                      productSelectHtml = `
  5533.                         <select name=\"productId[]\" class=\"form-control product-select-row\" data-uuid=\"\${uuid}\">
  5534.                              \${productOptions}
  5535.                         </select>
  5536.                      `;
  5537.                 }
  5538.                 
  5539.                 // Unallocated Hidden Inputs
  5540.                 const unAllocatedHidens = !isAvoir ? `
  5541.                     <input type=\"hidden\" name=\"warehouseid[]\" value=\"\${value.warehouse}\">
  5542.                     <input type=\"hidden\" name=\"length[]\" value=\"\${value.length || ''}\">
  5543.                     <input type=\"hidden\" name=\"width[]\" value=\"\${value.width || ''}\">
  5544.                     <input type=\"hidden\" name=\"thickness[]\" value=\"\${value.thickness || ''}\">
  5545.                     <input type=\"hidden\" name=\"cost[]\" value=\"\${value.cost || ''}\">
  5546.                     <input type=\"hidden\" name=\"unAllocatedQuantity[]\" class=\"unallocated-quantity-hidden\" value=\"\${value.unAllocatedQuantity}\" data-uuid=\"\${uuid}\">
  5547.                     <input type=\"hidden\" name=\"unAllocatedQuantityUnit[]\" class=\"unallocated-unit-hidden\" value=\"\" data-uuid=\"\${uuid}\">
  5548.                 ` : '';
  5549.                 // Quantity Unit Select
  5550.                 let quantityUnitSelectHtml = '';
  5551.                 if(isAvoir){
  5552.                      quantityUnitSelectHtml = `
  5553.                         <select class=\"custom-select custom-select-sm\" disabled>
  5554.                             <option>-</option>
  5555.                         </select>
  5556.                      `;
  5557.                 } else {
  5558.                     quantityUnitSelectHtml = `
  5559.                         <select class=\"custom-select custom-select-sm quantity-unit-select\"
  5560.                                 name=\"quantityUnit[]\" data-uuid=\"\${uuid}\">
  5561.                             <option value=\"\">-</option>
  5562.                         </select>
  5563.                     `;
  5564.                 }
  5565.                 // Discount Options
  5566.                 let discountOptionsHtml = '';
  5567.                 const discounts = [0, 1, 2, 3, 4, 5, 20, 30, 100];
  5568.                 discounts.forEach(function(d){
  5569.                     discountOptionsHtml += `<option value=\"\${d}\" \${value.discount === d ? 'selected' : ''}>% \${d}</option>`;
  5570.                 });
  5571.                 
  5572.                 // Tax Options
  5573.                 let taxOptionsHtml = '';
  5574.                 const taxes = [0, 10, 20];
  5575.                 taxes.forEach(function(t){
  5576.                     const disabledAttr = t === 0 ? 'disabled' : '';
  5577.                     taxOptionsHtml += `<option value=\"\${t}\" \${value.tax === t ? 'selected' : ''} \${disabledAttr}>% \${t}</option>`;
  5578.                 });
  5579.                 const quantityVal = value.quantity !== undefined ? value.quantity.toFixed(2) : '1.00';
  5580.                 const unitPriceVal = value.unitPrice !== undefined ? value.unitPrice.toFixed(2) : '0.00';
  5581.                 const totalPriceVal = value.totalPurchasePrice !== undefined ? value.totalPurchasePrice.toFixed(2) : '0.00';
  5582.                 // Only standard rows get the name=\"...\" attributes to be submitted
  5583.                 const nameAttr = isAvoir ? '' : 'name=';
  5584.                 return `
  5585.                     <tr id=\"\${uuid}\" data-product-id=\"\${value.productid || ''}\" class=\"\${rowClass}\">
  5586.                         <td>\${infoButtonHtml}</td>
  5587.                         <td class=\"product-select-cell\">
  5588.                             \${productSelectHtml}
  5589.                             \${unAllocatedHidens}
  5590.                         </td>
  5591.                         <td>
  5592.                             <div class=\"input-group input-group-sm\" style=\"max-width: 220px;\">
  5593.                                 <input type=\"number\" \${!isAvoir ? 'name=\"quantity[]\"' : ''}
  5594.                                        class=\"form-control quantity-input-row mask-money \${isAvoir ? 'text-danger' : ''}\"
  5595.                                        value=\"\${quantityVal}\"
  5596.                                        min=\"0\" step=\"0.01\" data-uuid=\"\${uuid}\" \${inputReadonly}>
  5597.                                 <div class=\"input-group-append\">
  5598.                                     \${quantityUnitSelectHtml}
  5599.                                 </div>
  5600.                             </div>
  5601.                         </td>
  5602.                         <td>
  5603.                             <input type=\"text\" \${!isAvoir ? 'name=\"unitPrice[]\"' : ''}
  5604.                                    class=\"form-control form-control-sm price-input-row mask-money \${isAvoir ? 'text-danger' : ''}\"
  5605.                                    value=\"\${unitPriceVal}\"
  5606.                                    min=\"0\" step=\"0.01\" data-uuid=\"\${uuid}\"
  5607.                                    placeholder=\"Birim Fiyat\" \${inputReadonly}>
  5608.                         </td>
  5609.                         <td>
  5610.                             <select \${!isAvoir ? 'name=\"discount[]\"' : ''} class=\"form-control form-control-sm discount-select-row\"
  5611.                                     data-uuid=\"\${uuid}\" \${readonly}>
  5612.                                 \${discountOptionsHtml}
  5613.                             </select>
  5614.                         </td>
  5615.                         <td>
  5616.                             <select \${!isAvoir ? 'name=\"tax[]\"' : ''} class=\"form-control form-control-sm tax-select-row\"
  5617.                                     data-uuid=\"\${uuid}\" \${readonly}>
  5618.                                 \${taxOptionsHtml}
  5619.                             </select>
  5620.                         </td>
  5621.                         <td class=\"text-right\">
  5622.                             <input \${!isAvoir ? 'name=\"totalPrice[]\"' : ''} type=\"text\"
  5623.                                    class=\"form-control form-control-sm total-input-row mask-money \${isAvoir ? 'text-danger font-weight-bold' : ''}\"
  5624.                                    value=\"\${totalPriceVal}\"
  5625.                                    data-uuid=\"\${uuid}\"
  5626.                                    placeholder=\"Toplam\" \${inputReadonly}/>
  5627.                         </td>
  5628.                         <td class=\"text-center\">
  5629.                             \${actionButtonsHtml}
  5630.                         </td>
  5631.                     </tr>
  5632.                     \${!isAvoir ? `
  5633.                     <tr class=\"info-details-row-class\" data-uuid=\"\${uuid}\" style=\"display: none;\">
  5634.                         <td colspan=\"8\" style=\"padding: 0; border-top: none;\">
  5635.                             <div class=\"info-details-content-class p-3\" style=\"display: none;\">
  5636.                                 <div class=\"row\">
  5637.                                     <div class=\"col-md-3\"><strong>Ürün Adı:</strong> \${value.productName}</div>
  5638.                                     <div class=\"col-md-3\"><strong>Kod:</strong> \${value.code}</div>
  5639.                                     <div class=\"col-md-3\"><strong>Ölçü:</strong> \${value.measurement}</div>
  5640.                                     <div class=\"col-md-3\"><strong>Uzunluk:</strong> \${value.length || '-'}</div>
  5641.                                 </div>
  5642.                                 <div class=\"row mt-2\">
  5643.                                     <div class=\"col-md-3\"><strong>Genişlik:</strong> \${value.width || '-'}</div>
  5644.                                     <div class=\"col-md-3\"><strong>Kalınlık:</strong> \${value.thickness || '-'}</div>
  5645.                                     <div class=\"col-md-3\"><strong>Maliyet:</strong> \${(value.cost || 0).toFixed(2)} €</div>
  5646.                                     <div class=\"col-md-3\"><strong>Depo:</strong> \${value.warehouse}</div>
  5647.                                 </div>
  5648.                             </div>
  5649.                         </td>
  5650.                     </tr>` : ''}
  5651.                 `;
  5652.             }
  5653.             // Render sold products table rows with complete editing capabilities
  5654.             // TODO: Seçilen ürün eğer hizmet ise dropdown da hizmet adını kaydedildiği şekilde göster
  5655.             function fetchSoldListRows() {
  5656.                 \$('#product-list-table-tbody').empty();
  5657.                 soldList.forEach(function(value, index) {
  5658.                     const rowHtml = generateProductRowHtml(value, { isAvoir: false });
  5659.                     \$('#product-list-table-tbody').append(rowHtml);
  5660.                     \$(`.product-select-row[data-uuid=\"\${value.uuid}\"]`).select2({
  5661.                         theme: 'bootstrap4',
  5662.                         dropdownCssClass: 'custom-select-dropdown',
  5663.                         placeholder: 'Ürün Seçin',
  5664.                         allowClear: true
  5665.                     });
  5666.                     applyMasks();
  5667.                     // Load measurement units for each product row with default unit
  5668.                     const product = products.find(p => p.productid === value.productid);
  5669.                     const defaultUnitId = product ? product.measurementUnitId : null;
  5670.                     const preferredUnitId = (value.selectedUnitId !== undefined && value.selectedUnitId !== null && value.selectedUnitId !== '') ? value.selectedUnitId : defaultUnitId;
  5671.                     loadMeasurementUnitsForRow(value.productid, value.uuid, preferredUnitId);
  5672.                 });
  5673.                 // Check for Gift Voucher amount and add AVOIR row using reusable component
  5674.                 const totalVoucherAmount = calculateTotalGiftVoucherAmount();
  5675.                 if (!totalVoucherAmount.isZero()) {
  5676.                      const avoirItem = {
  5677.                         uuid: 'avoir-row',
  5678.                         productid: null,
  5679.                         productName: 'AVOIR',
  5680.                         quantity: 1,
  5681.                         unAllocatedQuantity: 0,
  5682.                         unitPrice: totalVoucherAmount.times(-1).toNumber(), // Negative unit price
  5683.                         totalPurchasePrice: totalVoucherAmount.times(-1).toNumber(), // Negative total
  5684.                         discount: 0,
  5685.                         tax: 0
  5686.                      };
  5687.                      
  5688.                      // We override the visual display of the price to be positive in the input if desired, 
  5689.                      // OR we keep it negative to indicate deduction. 
  5690.                      // The user request screenshot showed \"AVOIR\" in red. 
  5691.                      // Standard AVOIR usually implies negative context but let's stick to the styling.
  5692.                      // IMPORTANT: The screenshot usually shows the total as negative, so unit price should likely be negative too.
  5693.                      // Wait, if Quantity is 1 and Total is -Amount, Unit Price must be -Amount.
  5694.                      
  5695.                      const avoirRowHtml = generateProductRowHtml(avoirItem, { isAvoir: true });
  5696.                      \$('#product-list-table-tbody').append(avoirRowHtml);
  5697.                 }
  5698.                 fetchStocks();
  5699.                 updateProductSelect();
  5700.                 updateTotalAmounts();
  5701.                 \$('#warehouseselect').attr('disabled', soldList.length > 0);
  5702.             }
  5703.             // --- GIFT VOUCHER INTEGRATION ---
  5704.             // Set default ID to 0 or a value that won't match if not found.
  5705.             // Using Twig to find the ID.
  5706.             const PAYMENT_METHOD_GIFT_VOUCHER_ID = (function() {
  5707.                 {% for pm in paymentMethods %}
  5708.                     {% if pm.name == 'Hediye Çeki' or pm.name == 'Gift Voucher' %}
  5709.                         return \"{{ pm.id }}\";
  5710.                     {% endif %}
  5711.                 {% endfor %}
  5712.                 return null;
  5713.             })();
  5714.             function calculateTotalGiftVoucherAmount() {
  5715.                 let totalVoucher = new Decimal(0);
  5716.                 if (!PAYMENT_METHOD_GIFT_VOUCHER_ID) return totalVoucher;
  5717.                 payments.forEach(function(p) {
  5718.                     if (String(p.paymentMethod) === String(PAYMENT_METHOD_GIFT_VOUCHER_ID)) {
  5719.                         totalVoucher = totalVoucher.plus(convertToDecimal(p.amount));
  5720.                     }
  5721.                 });
  5722.                 return totalVoucher;
  5723.             }
  5724.             // ---------------------------------
  5725.             function renderServiceEditBtn(value){
  5726.               const product = products.find(p => p.productid === value.productid);
  5727.               if (isProductService(product.productid)) {
  5728.                 return `
  5729.                   <button type=\"button\"
  5730.                           class=\"btn btn-warning btn-sm edit-service-button\"
  5731.                           data-uuid=\"\${value.uuid}\"
  5732.                           title=\"Servisi Güncelle\">
  5733.                     <i class=\"fas fa-edit\"></i>
  5734.                   </button>
  5735.                 `;
  5736.               }
  5737.               return ''; // değilse hiç ekleme
  5738.             }
  5739.             function calculateRowFinancials(source) {
  5740.                 const quantity = convertToDecimal(source.quantity || 0);
  5741.                 const unAllocatedQuantity = convertToDecimal(source.unAllocatedQuantity || 0);
  5742.                 const unitPrice = convertToDecimal(source.unitPrice || 0);
  5743.                 const discountPercentage = convertToDecimal(source.discount || 0);
  5744.                 const taxPercentage = convertToDecimal(source.tax || 0);
  5745.                 const totalQuantity = quantity.plus(unAllocatedQuantity);
  5746.                 if (totalQuantity.isZero()) {
  5747.                     return {
  5748.                         subtotal: new Decimal(0),
  5749.                         discountAmount: new Decimal(0),
  5750.                         afterDiscount: new Decimal(0),
  5751.                         taxAmount: new Decimal(0),
  5752.                         total: new Decimal(0),
  5753.                         totalRounded: new Decimal(0),
  5754.                         taxPercentage
  5755.                     };
  5756.                 }
  5757.                 const subtotal = totalQuantity.mul(unitPrice);
  5758.                 const discountAmount = subtotal.mul(discountPercentage.div(100));
  5759.                 const afterDiscount = subtotal.minus(discountAmount);
  5760.                 const taxAmount = afterDiscount.mul(taxPercentage.div(100));
  5761.                 const total = afterDiscount.plus(taxAmount);
  5762.                 return {
  5763.                     subtotal,
  5764.                     discountAmount,
  5765.                     afterDiscount,
  5766.                     taxAmount,
  5767.                     total,
  5768.                     totalRounded: total.toDecimalPlaces(2, MONEY_ROUNDING_MODE),
  5769.                     taxPercentage
  5770.                 };
  5771.             }
  5772.             function aggregateSoldTotals() {
  5773.                 const aggregation = {
  5774.                     grossTotal: new Decimal(0),
  5775.                     totalDiscount: new Decimal(0),
  5776.                     subtotal: new Decimal(0),
  5777.                     tax: new Decimal(0),
  5778.                     grandTotal: new Decimal(0),
  5779.                     byTaxRate: {}
  5780.                 };
  5781.                 soldList.forEach(function(item) {
  5782.                     // item.totalPurchasePrice'ı kullan (manuel veya otomatik hesaplanmış)
  5783.                     const itemTotal = convertToDecimal(item.totalPurchasePrice || 0);
  5784.                     // Toplam üzerinden geriye doğru hesaplama
  5785.                     // Formül: total = subtotal × (1 - discount%) × (1 + tax%)
  5786.                     // Ters formül: afterDiscount = total / (1 + tax%)
  5787.                     //              subtotal = afterDiscount / (1 - discount%)
  5788.                     const taxPercentage = convertToDecimal(item.tax || 0);
  5789.                     const discountPercentage = convertToDecimal(item.discount || 0);
  5790.                     const taxMultiplier = new Decimal(1).plus(taxPercentage.div(100));
  5791.                     // Adım 1: KDV'yi çıkar → İndirim sonrası tutarı bul
  5792.                     // afterDiscount = total / (1 + tax%)
  5793.                     const afterDiscount = itemTotal.div(taxMultiplier);
  5794.                     // Adım 2: KDV tutarını hesapla
  5795.                     // taxAmount = afterDiscount × tax%
  5796.                     const taxAmount = afterDiscount.mul(taxPercentage.div(100));
  5797.                     // NOT: \"Ara Toplam\" (subtotal) = afterDiscount (indirim uygulanmış tutar)
  5798.                     // Çünkü görüntülenen \"Ara Toplam\" indirim sonrası, KDV öncesi tutar
  5799.                     // Calculate Gross (before discount)
  5800.                     const quantity = convertToDecimal(item.quantity).plus(convertToDecimal(item.unAllocatedQuantity));
  5801.                     const unitPrice = convertToDecimal(item.unitPrice); 
  5802.                     const grossLine = quantity.mul(unitPrice);
  5803.                     
  5804.                     // Calculate Discount derived from Gross vs Net
  5805.                     const discountAmount = grossLine.minus(afterDiscount);
  5806.                     aggregation.grossTotal = aggregation.grossTotal.plus(grossLine);
  5807.                     aggregation.totalDiscount = aggregation.totalDiscount.plus(discountAmount);
  5808.                     aggregation.subtotal = aggregation.subtotal.plus(afterDiscount);
  5809.                     aggregation.tax = aggregation.tax.plus(taxAmount);
  5810.                     aggregation.grandTotal = aggregation.grandTotal.plus(itemTotal);
  5811.                     const rateKey = taxPercentage.toFixed(4);
  5812.                     if (!aggregation.byTaxRate[rateKey]) {
  5813.                         aggregation.byTaxRate[rateKey] = {
  5814.                             rate: taxPercentage,
  5815.                             amount: new Decimal(0)
  5816.                         };
  5817.                     }
  5818.                     aggregation.byTaxRate[rateKey].amount = aggregation.byTaxRate[rateKey].amount.plus(taxAmount);
  5819.                 });
  5820.                 aggregation.subtotalRounded = aggregation.subtotal.toDecimalPlaces(2, MONEY_ROUNDING_MODE);
  5821.                 aggregation.taxRounded = aggregation.tax.toDecimalPlaces(2, MONEY_ROUNDING_MODE);
  5822.                 aggregation.grandTotalRounded = aggregation.grandTotal.toDecimalPlaces(2, MONEY_ROUNDING_MODE);
  5823.                 return aggregation;
  5824.             }
  5825.             // Track which row is being updated to prevent circular updates
  5826.             let rowUpdatingFromTotal = {};
  5827.             let rowUpdatingFromUnitPrice = {};
  5828.             // Track rows where total was manually entered (should not recalculate total)
  5829.             let rowHasManualTotal = {};
  5830.             function updateSoldProductFromRow(uuid) {
  5831.                 const itemIndex = soldList.findIndex(item => item.uuid === uuid);
  5832.                 if (itemIndex === -1) {
  5833.                     return;
  5834.                 }
  5835.                 // Eğer bu satır toplam tarafından güncelleniyorsa, tekrar toplam güncelleme
  5836.                 if(rowUpdatingFromTotal[uuid]) {
  5837.                     return;
  5838.                 }
  5839.                 rowUpdatingFromUnitPrice[uuid] = true;
  5840.                 const \$row = \$(`#\${uuid}`);
  5841.                 const quantity = convertToDecimal(\$row.find('.quantity-input-row').val()).toNumber();
  5842.                 const unitPrice = convertToDecimal(\$row.find('.price-input-row').val()).toNumber();
  5843.                 const discount = convertToDecimal(\$row.find('.discount-select-row').val()).toNumber();
  5844.                 const tax = convertToDecimal(\$row.find('.tax-select-row').val()).toNumber();
  5845.                 soldList[itemIndex].quantity = quantity;
  5846.                 soldList[itemIndex].unitPrice = unitPrice;
  5847.                 soldList[itemIndex].discount = discount;
  5848.                 soldList[itemIndex].tax = tax;
  5849.                 const selectedUnitId = \$row.find('.quantity-unit-select').val();
  5850.                 computeBaseUnitQuantity(soldList[itemIndex].productid, selectedUnitId, quantity, function(baseQty){
  5851.                     soldList[itemIndex].baseUnitQuantity = convertToDecimal(baseQty || quantity).toNumber();
  5852.                 });
  5853.                 // Eğer bu satırda manuel toplam girildiyse, toplam sabit kalmalı, sadece birim fiyat güncellensin
  5854.                 if (rowHasManualTotal[uuid]) {
  5855.                     // Manuel toplam korunuyor, birim fiyatı tersine hesapla
  5856.                     const manualTotal = convertToDecimal(soldList[itemIndex].totalPurchasePrice);
  5857.                     const totalQuantity = convertToDecimal(quantity).plus(convertToDecimal(soldList[itemIndex].unAllocatedQuantity || 0));
  5858.                     if (!totalQuantity.isZero()) {
  5859.                         const discountMultiplier = new Decimal(1).minus(convertToDecimal(discount).div(100));
  5860.                         const taxMultiplier = new Decimal(1).plus(convertToDecimal(tax).div(100));
  5861.                         if (discountMultiplier.isZero()) {
  5862.                             soldList[itemIndex].unitPrice = 0;
  5863.                             \$row.find('.price-input-row').val('0.00');
  5864.                         } else if (!taxMultiplier.isZero()) {
  5865.                             const calculatedUnitPrice = manualTotal
  5866.                                 .div(taxMultiplier)
  5867.                                 .div(discountMultiplier)
  5868.                                 .div(totalQuantity)
  5869.                                 .toDecimalPlaces(6, MONEY_ROUNDING_MODE);
  5870.                             soldList[itemIndex].unitPrice = calculatedUnitPrice.toNumber();
  5871.                             \$row.find('.price-input-row').val(calculatedUnitPrice.toDecimalPlaces(2, MONEY_ROUNDING_MODE).toFixed(2));
  5872.                         }
  5873.                     }
  5874.                     // Toplam input'u DEĞİŞTİRME - manuel değer korunuyor
  5875.                 } else {
  5876.                     // Normal hesaplama - toplam otomatik hesaplansın
  5877.                     const rowTotals = calculateRowFinancials(soldList[itemIndex]);
  5878.                     soldList[itemIndex].totalPurchasePrice = rowTotals.totalRounded.toNumber();
  5879.                     \$row.find('.total-input-row').val(rowTotals.totalRounded.toFixed(2));
  5880.                 }
  5881.                 updateTotalAmounts();
  5882.                 fetchStocks();
  5883.                 fetchPaymentForm();
  5884.                 setTimeout(function(){ delete rowUpdatingFromUnitPrice[uuid]; }, 0);
  5885.             }
  5886.             // Toplam tutar değiştirildiğinde birim fiyatı tersine hesaplar
  5887.             function updateUnitPriceFromTotal(uuid) {
  5888.                 const itemIndex = soldList.findIndex(item => item.uuid === uuid);
  5889.                 if (itemIndex === -1) {
  5890.                     return;
  5891.                 }
  5892.                 // Eğer bu satır birim fiyat tarafından güncelleniyorsa, döngüyü engelle
  5893.                 if(rowUpdatingFromUnitPrice[uuid]) {
  5894.                     return;
  5895.                 }
  5896.                 rowUpdatingFromTotal[uuid] = true;
  5897.                 // ÖNEMLİ: Toplam manuel girildi, bu satırı işaretle
  5898.                 rowHasManualTotal[uuid] = true;
  5899.                 const \$row = \$(`#\${uuid}`);
  5900.                 const totalValue = convertToDecimal(\$row.find('.total-input-row').val());
  5901.                 const item = soldList[itemIndex];
  5902.                 const totalQuantity = convertToDecimal(item.quantity || 0).plus(convertToDecimal(item.unAllocatedQuantity || 0));
  5903.                 if (totalQuantity.isZero()) {
  5904.                     setTimeout(function(){ delete rowUpdatingFromTotal[uuid]; }, 0);
  5905.                     return;
  5906.                 }
  5907.                 // Manuel girilen toplam değerini kaydet
  5908.                 soldList[itemIndex].totalPurchasePrice = totalValue.toNumber();
  5909.                 // Eğer toplam 0 ise, birim fiyat da 0 olmalı
  5910.                 if (totalValue.isZero()) {
  5911.                     \$row.find('.price-input-row').val('0.00');
  5912.                     soldList[itemIndex].unitPrice = 0;
  5913.                     updateTotalAmounts();
  5914.                     fetchStocks();
  5915.                     fetchPaymentForm();
  5916.                     setTimeout(function(){ delete rowUpdatingFromTotal[uuid]; }, 0);
  5917.                     return;
  5918.                 }
  5919.                 const discountMultiplier = new Decimal(1).minus(convertToDecimal(item.discount || 0).div(100));
  5920.                 const taxMultiplier = new Decimal(1).plus(convertToDecimal(item.tax || 0).div(100));
  5921.                 // %100 indirimde discountMultiplier = 0 olur, bu durumda birim fiyat 0 olmalı
  5922.                 if (discountMultiplier.isZero()) {
  5923.                     \$row.find('.price-input-row').val('0.00');
  5924.                     soldList[itemIndex].unitPrice = 0;
  5925.                     updateTotalAmounts();
  5926.                     fetchStocks();
  5927.                     fetchPaymentForm();
  5928.                     setTimeout(function(){ delete rowUpdatingFromTotal[uuid]; }, 0);
  5929.                     return;
  5930.                 }
  5931.                 if (taxMultiplier.isZero()) {
  5932.                     setTimeout(function(){ delete rowUpdatingFromTotal[uuid]; }, 0);
  5933.                     return;
  5934.                 }
  5935.                 // Formül: unitPrice = total / ((1 + tax%) * (1 - discount%) * quantity)
  5936.                 const unitPrice = totalValue
  5937.                     .div(taxMultiplier)
  5938.                     .div(discountMultiplier)
  5939.                     .div(totalQuantity)
  5940.                     .toDecimalPlaces(6, MONEY_ROUNDING_MODE);
  5941.                 \$row.find('.price-input-row').val(unitPrice.toDecimalPlaces(2, MONEY_ROUNDING_MODE).toFixed(2));
  5942.                 soldList[itemIndex].unitPrice = unitPrice.toNumber();
  5943.                 // Sadece stok ve genel toplamları güncelle, satır toplamını değiştirme
  5944.                 updateTotalAmounts();
  5945.                 fetchStocks();
  5946.                 fetchPaymentForm();
  5947.                 setTimeout(function(){ delete rowUpdatingFromTotal[uuid]; }, 0);
  5948.             }
  5949.             // =============================================================================
  5950.             // WAREHOUSE SELECTION EVENT HANDLER
  5951.             // =============================================================================
  5952.             // Handle warehouse selection change
  5953.             \$('#warehouseselect').on('change', function() {
  5954.                 getProductsFromWarehouse();
  5955.             });
  5956.             // Auto-select warehouse if there is only one
  5957.             var \$warehouseSelect = \$('#warehouseselect');
  5958.             if (\$warehouseSelect.find('option').length === 2 && \$warehouseSelect.val() === \"\") {
  5959.                  var firstWarehouseVal = \$warehouseSelect.find('option').eq(1).val();
  5960.                  \$warehouseSelect.val(firstWarehouseVal).trigger('change');
  5961.             }
  5962.             // Load measurement units for a specific product row (with caching)
  5963.             let measurementUnitsCache = {};
  5964.             function loadMeasurementUnitsForRow(productId, uuid, defaultUnitId = null) {
  5965.                 // Check cache first
  5966.                 if (measurementUnitsCache[productId]) {
  5967.                     populateUnitSelectForRow(uuid, measurementUnitsCache[productId], defaultUnitId);
  5968.                     return;
  5969.                 }
  5970.                 // Load from server if not cached
  5971.                 \$.get('/product/' + productId + '/measurement-units', function(units) {
  5972.                     // Cache the units
  5973.                     measurementUnitsCache[productId] = units || [];
  5974.                     populateUnitSelectForRow(uuid, units, defaultUnitId);
  5975.                 }).fail(function() {
  5976.                     console.log('Failed to load measurement units for product:', productId);
  5977.                     measurementUnitsCache[productId] = []; // Cache empty array to prevent repeated requests
  5978.                 });
  5979.             }
  5980.             // Populate unit select dropdown for a specific row
  5981.             function populateUnitSelectForRow(uuid, units, defaultUnitId = null) {
  5982.                 const \$select = \$(`.quantity-unit-select[data-uuid=\"\${uuid}\"]`);
  5983.                 \$select.empty();
  5984.                 if (Array.isArray(units) && units.length > 0) {
  5985.                     units.forEach(function(unit) {
  5986.                         const isSelected = defaultUnitId !== null && defaultUnitId !== undefined && defaultUnitId !== '' && String(unit.id) === String(defaultUnitId);
  5987.                         const selectedAttr = isSelected ? ' selected' : '';
  5988.                         \$select.append('<option value=\"' + unit.id + '\"' + selectedAttr + '>' + unit.symbol + '</option>');
  5989.                     });
  5990.                     if (units.length === 1) {
  5991.                         \$select.prop('disabled', true);
  5992.                     } else {
  5993.                         \$select.prop('disabled', false);
  5994.                     }
  5995.                 } else {
  5996.                     \$select.append('<option value=\"\">-</option>');
  5997.                     \$select.prop('disabled', false);
  5998.                 }
  5999.             }
  6000.             // Update total amounts in footer
  6001.             function updateTotalAmounts() {
  6002.                 const taxLabelPrefix = \"TVA\";
  6003.                 const taxTotalLabel = \"{{ 'total'|trans|e('js') }}\";
  6004.                 const formatTaxRate = function(rateDecimal) {
  6005.                     const rateNumber = convertToDecimal(rateDecimal || 0).toNumber();
  6006.                     if (!isFinite(rateNumber)) {
  6007.                         return \"0\";
  6008.                     }
  6009.                     if (Math.abs(rateNumber % 1) < 1e-6) {
  6010.                         return rateNumber.toFixed(0);
  6011.                     }
  6012.                     return rateNumber.toFixed(2).replace(/\\.?0+\$/, \"\");
  6013.                 };
  6014.                 const totals = aggregateSoldTotals();
  6015.                 const \$tfoot = \$(\"#product-list-table tfoot\");
  6016.                 \$tfoot.empty();
  6017.                 // Helper to create row
  6018.                 const addRow = (label, value, isBold=false, colorClass='') => {
  6019.                     const row = \$(`<tr class=\"summary-row \${isBold ? 'font-weight-bold' : ''} \${colorClass}\">
  6020.                         <td colspan=\"8\">
  6021.                             <div class=\"sale-summary-row\">
  6022.                                 <span class=\"summary-label\">\${label}</span>
  6023.                                 <span class=\"summary-value\">\${formatCurrency(value)}</span>
  6024.                             </div>
  6025.                         </td>
  6026.                     </tr>`);
  6027.                     \$tfoot.append(row);
  6028.                 };
  6029.                 // 1. Total H.T. (Gross)
  6030.                 addRow('Total H.T.:', totals.grossTotal, true);
  6031.                 // 2. Remise
  6032.                 if (!totals.totalDiscount.isZero() && totals.totalDiscount.toNumber() > 0.005) {
  6033.                      const \$row = \$(`<tr class=\"summary-row\">
  6034.                         <td colspan=\"8\">
  6035.                             <div class=\"sale-summary-row\">
  6036.                                 <span class=\"summary-label\">Remise:</span>
  6037.                                 <span class=\"summary-value\">\${formatCurrency(totals.totalDiscount.negated())}</span>
  6038.                             </div>
  6039.                         </td>
  6040.                     </tr>`);
  6041.                     \$tfoot.append(\$row);
  6042.                 }
  6043.                 // 3. Total H.T. (Net)
  6044.                 addRow('Total H.T.:', totals.subtotal, true);
  6045.                 // 4. AVOIR
  6046.                 const totalVoucherAmount = calculateTotalGiftVoucherAmount();
  6047.                 let finalTotal = totals.grandTotalRounded; // Assuming totals.grandTotalRounded is available in result? Yes
  6048.                 // Wait, aggregateSoldTotals returns grandTotalRounded.
  6049.                 // But calculateSaleSummary in edit.html.twig returned summary.roundedTotal.
  6050.                 
  6051.                 if (!totalVoucherAmount.isZero()) {
  6052.                     const \$avoirRow = \$(`<tr class=\"summary-row text-danger font-weight-bold\">
  6053.                         <td colspan=\"8\">
  6054.                             <div class=\"sale-summary-row\">
  6055.                                 <span class=\"summary-label\">AVOIR:</span>
  6056.                                 <span class=\"summary-value\">-\${formatCurrency(totalVoucherAmount)}</span>
  6057.                             </div>
  6058.                         </td>
  6059.                     </tr>`);
  6060.                     \$tfoot.append(\$avoirRow);
  6061.                     
  6062.                     finalTotal = finalTotal.minus(totalVoucherAmount);
  6063.                 }
  6064.                 // 5. TVA
  6065.                 const taxEntries = Object.values(totals.byTaxRate)
  6066.                     .filter(function(entry) { return !entry.amount.isZero(); })
  6067.                     .sort(function(a, b) { return a.rate.toNumber() - b.rate.toNumber(); });
  6068.                 if (taxEntries.length) {
  6069.                     taxEntries.forEach(function(entry) {
  6070.                          addRow(taxLabelPrefix + \" (\" + formatTaxRate(entry.rate) + \"%):\", entry.amount);
  6071.                     });
  6072.                 } else {
  6073.                      addRow(taxLabelPrefix + \" (0%):\", 0);
  6074.                 }
  6075.                 // 6. TOTAL
  6076.                 const \$totalRow = \$(`<tr class=\"total-row summary-row font-weight-bold\">
  6077.                     <td colspan=\"8\">
  6078.                         <div class=\"sale-summary-row summary-total\">
  6079.                             <span class=\"summary-label\">TOTAL À PAYER (EUR):</span>
  6080.                             <span class=\"summary-value display-5\">\${formatCurrency(finalTotal)}</span>
  6081.                         </div>
  6082.                     </td>
  6083.                 </tr>`);
  6084.                 \$tfoot.append(\$totalRow);
  6085.                 calculateAndWriteDiffBetweenPaymentAndSolds();
  6086.             }
  6087.             // Update sold list item by UUID
  6088.             function updateSoldListItem(uuid, field, value) {
  6089.                 const itemIndex = soldList.findIndex(item => item.uuid === uuid);
  6090.                 if (itemIndex === -1) {
  6091.                     return;
  6092.                 }
  6093.                 soldList[itemIndex][field] = convertToDecimal(value).toNumber();
  6094.                 updateSoldProductFromRow(uuid);
  6095.             }
  6096.             // Satıştaki miktarları listeden düşme Un Allocated HARİÇ tutulur
  6097.             function fetchStocks() {
  6098.                 // soldList'i productid'e göre grupla
  6099.                 const groupedSoldList = soldList.reduce((acc, soldProduct) => {
  6100.                     if (!acc[soldProduct.productid]) {
  6101.                         acc[soldProduct.productid] = 0;
  6102.                     }
  6103.                     acc[soldProduct.productid] += convertToDecimal(soldProduct.baseUnitQuantity).toNumber();
  6104.                     return acc;
  6105.                 }, {});
  6106.                 // products listesindeki totalQuantity'yi güncelle
  6107.                 products.forEach(product => {
  6108.                     if (groupedSoldList[product.productid]) {
  6109.                         const totalSoldQuantity = groupedSoldList[product.productid];
  6110.                         product.quantity = roundStockToDecimal(convertToDecimal(product.totalQuantity - totalSoldQuantity).toNumber());
  6111.                     } else {
  6112.                         // Eğer soldList'te bu ürün yoksa, quantity aynı kalır
  6113.                         product.quantity = roundStockToDecimal(convertToDecimal(product.totalQuantity).toNumber());
  6114.                     }
  6115.                 });
  6116.                 calculateAndWriteDiffBetweenPaymentAndSolds();
  6117.             }
  6118.             function getTotalSoldAmount() {
  6119.                 return aggregateSoldTotals().grandTotalRounded.toNumber();
  6120.             }
  6121.             \$(document).on('blur', '#payment-list-table-tbody .payment-amount-input', function() {
  6122.                 // Buraya kod eklenebilir
  6123.             });
  6124.             // Gelen değeri decimale çevirme
  6125.             function convertToDecimal(value) {
  6126.                 try {
  6127.                     if (value instanceof Decimal) {
  6128.                         return value;
  6129.                     }
  6130.                     if (value === undefined || value === null) {
  6131.                         return new Decimal(0);
  6132.                     }
  6133.                     if (typeof value === 'number') {
  6134.                         if (!isFinite(value) || isNaN(value)) {
  6135.                             return new Decimal(0);
  6136.                         }
  6137.                         return new Decimal(value);
  6138.                     }
  6139.                     if (typeof value === 'string') {
  6140.                         // Keep digits, minus, dot and comma; strip others
  6141.                         var sanitized = value.replace(/[^0-9.,-]/g, '').replace(/,/g, '').trim();
  6142.                         if (sanitized === '' || sanitized === '-' || sanitized === '.' || sanitized === '-.') {
  6143.                             return new Decimal(0);
  6144.                         }
  6145.                         return new Decimal(sanitized);
  6146.                     }
  6147.                     return new Decimal(0);
  6148.                 } catch (e) {
  6149.                     return new Decimal(0);
  6150.                 }
  6151.             }
  6152.             // Seçilen ürünün birimini dropdown'da gösterme (handled by main product select handler)
  6153.             function clearUnitSelects(){
  6154.                 \$('#adder-quantity-unit-select').empty().append('<option value=\"\">-</option>');
  6155.                 \$('#adder-unallocated-quantity-unit-select').empty().append('<option value=\"\">-</option>');
  6156.                 \$('#modal-unallocated-unit').empty().append('<option value=\"\">-</option>');
  6157.             }
  6158.             // Select içine çevrilebilir birimleri koyuyor
  6159.             function populateSelectWithUnits(\$select, units) {
  6160.                 \$select.empty();
  6161.                 if (Array.isArray(units) && units.length > 0) {
  6162.                     units.forEach(function(unit) {
  6163.                         \$select.append('<option value=\"' + unit.id + '\">' + unit.symbol + '</option>');
  6164.                     });
  6165.                     if (units.length === 1) {
  6166.                         \$select.prop('disabled', true);
  6167.                     } else {
  6168.                         \$select.prop('disabled', false);
  6169.                     }
  6170.                 } else {
  6171.                     \$select.append('<option value=\"\">-</option>');
  6172.                     \$select.prop('disabled', false);
  6173.                 }
  6174.             }
  6175.             // Ürünün çevrilebilir birimlerini select içine koyuyoruz.
  6176.             function refreshUnitSelectsForProduct(product) {
  6177.                 if (!product || !product.convertibleUnits) {
  6178.                     clearUnitSelects();
  6179.                     return;
  6180.                 }
  6181.                 populateSelectWithUnits(\$('#adder-quantity-unit-select'), product.convertibleUnits);
  6182.                 populateSelectWithUnits(\$('#adder-unallocated-quantity-unit-select'), product.convertibleUnits);
  6183.                 populateSelectWithUnits(\$('#modal-unallocated-unit'), product.convertibleUnits);
  6184.             }
  6185.             // TODO:  Birimler doldurulurken ilgili birimin karşılığındaki miktar yazılacak
  6186.             function fillUnitSelects(product){
  6187.                 // Check cache first
  6188.                 if (measurementUnitsCache[product.productid]) {
  6189.                     product.convertibleUnits = measurementUnitsCache[product.productid];
  6190.                     refreshUnitSelectsForProduct(product);
  6191.                     computeAndShowBaseUnitEquivalent();
  6192.                     return;
  6193.                 }
  6194.                 \$.get('/product/' + product.productid + '/measurement-units', function(units) {
  6195.                     // Cache the units
  6196.                     measurementUnitsCache[product.productid] = units || [];
  6197.                     // Store in product object
  6198.                     product.convertibleUnits = units || [];
  6199.                     // Update selects
  6200.                     refreshUnitSelectsForProduct(product);
  6201.                     // Set default unit as selected
  6202.                     if (product.measurementUnitId) {
  6203.                         \$('#adder-quantity-unit-select').val(product.measurementUnitId);
  6204.                         \$('#adder-unallocated-quantity-unit-select').val(product.measurementUnitId);
  6205.                         \$('#modal-unallocated-unit').val(product.measurementUnitId);
  6206.                     }
  6207.                     computeAndShowBaseUnitEquivalent();
  6208.                 });
  6209.             }
  6210.             // Seçilen birimde girilen miktarın, ürünün KENDİ birimindeki karşılığını hesaplar ve inputun altına küçük yazıyla gösterir
  6211.             function computeAndShowBaseUnitEquivalent() {
  6212.                 try {
  6213.                     const selectedProduct = getSelectedProduct();
  6214.                     if (!selectedProduct || !selectedProduct.productid) {
  6215.                         updateAllocatedQuantityHint('');
  6216.                         return;
  6217.                     }
  6218.                     const fromUnitId = \$('#adder-quantity-unit-select').val();
  6219.                     const qtyStr = \$('#adder-allocated-quantity').val();
  6220.                     // If base unit is selected, do not show duplicate label
  6221.                     if (fromUnitId && String(fromUnitId) === String(selectedProduct.measurementUnitId)) {
  6222.                         updateAllocatedQuantityHint('');
  6223.                         return;
  6224.                     }
  6225.                     if (!fromUnitId || fromUnitId === '' || qtyStr === '' || qtyStr === null) {
  6226.                         updateAllocatedQuantityHint('');
  6227.                         return;
  6228.                     }
  6229.                     const quantity = convertToDecimal(qtyStr).toNumber();
  6230.                     if (isNaN(quantity)) {
  6231.                         updateAllocatedQuantityHint('');
  6232.                         return;
  6233.                     }
  6234.                     \$.ajax({
  6235.                         url: '/admin/measurement/convert-to-product-unit',
  6236.                         method: 'POST',
  6237.                         dataType: 'json',
  6238.                         data: {
  6239.                             productId: selectedProduct.productid,
  6240.                             fromUnitId: fromUnitId,
  6241.                             quantity: quantity
  6242.                         },
  6243.                         success: function(resp) {
  6244.                             if (resp && resp.success) {
  6245.                                 const unitText = selectedProduct.measurementUnit ? (' ' + selectedProduct.measurementUnit) : '';
  6246.                                 updateAllocatedQuantityHint((Number(resp.result).toFixed(2)) + unitText);
  6247.                             } else {
  6248.                                 updateAllocatedQuantityHint('');
  6249.                             }
  6250.                         },
  6251.                         error: function() {
  6252.                             updateAllocatedQuantityHint('');
  6253.                         }
  6254.                     });
  6255.                 } catch (e) {
  6256.                     updateAllocatedQuantityHint('');
  6257.                 }
  6258.             }
  6259.             // Base unit tipinden miktar.
  6260.             function updateAllocatedQuantityHint(text) {
  6261.                 const \$group = \$('#adder-allocated-quantity').closest('.input-group');
  6262.                 if (\$('#allocated-quantity-converted-hint').length === 0) {
  6263.                     \$('<small id=\"allocated-quantity-converted-hint\" class=\"form-text text-muted\"></small>').insertAfter('#adder-quantity-unit-select');
  6264.                 }
  6265.                 \$('#allocated-quantity-converted-hint').text(text || '');
  6266.             }
  6267.             function roundToDecimal(value, decimalPlaces = 2) {
  6268.                 const decimalValue = new Decimal(value);
  6269.                 const roundedValue = decimalValue.toDecimalPlaces(decimalPlaces, Decimal.ROUND_UP);
  6270.                 return roundedValue.toNumber();
  6271.             }
  6272.             function roundStockToDecimal(value, decimalPlaces = 2) {
  6273.                 const decimalValue = new Decimal(value);
  6274.                 const roundedValue = decimalValue.toDecimalPlaces(decimalPlaces, Decimal.ROUND_DOWN);
  6275.                 return roundedValue.toNumber();
  6276.             }
  6277.             function selectProduct(productId) {
  6278.                 products.forEach(product => product.selected = false);
  6279.                 let product = products.find(product => product.productid === productId);
  6280.                 if (product) {
  6281.                     product.selected = true;
  6282.                 }
  6283.                 return products;
  6284.             }
  6285.             function getSelectedProduct() {
  6286.                 return products.find(product => product.selected === true);
  6287.             }
  6288.             // Ürün seçme selectini yeniden güncelleme.
  6289.             function updateProductSelect() {
  6290.                 \$('#productselect').empty();
  6291.                 \$('#productselect').append('<option value=\"0\" data-image=\"image-not-found.webp\">Ürün Seçin</option>');
  6292.                 \$.each(products, function(index, value) {
  6293.                     var image = value.image;
  6294.                     var option = '<option value=\"' + value.id + '\" data-image=\"' + image + '\" class=\"stockoption\">' + value.name + ' - ' + value.code + ' - ' + value.measurement + ' - ' + value.quantity + '</option>';
  6295.                     \$('#productselect').append(option);
  6296.                 });
  6297.                 \$('#productselect').attr('disabled', false);
  6298.             }
  6299.             \$('#products_sold_quantity').mask(\"##0.00\", {
  6300.                 reverse: true
  6301.             });
  6302.             \$('#adder-allocated-quantity').mask(\"##0.00\", {
  6303.                 reverse: true
  6304.             });
  6305.             \$('#adder-unallocated-quantity').mask(\"##0.00\", {
  6306.                 reverse: true
  6307.             });
  6308.             \$('#adder-price').mask(\"##0.00\", {
  6309.                 reverse: true
  6310.             });
  6311.             \$('#adder-total').mask(\"##0.00\", {
  6312.                 reverse: true
  6313.             });
  6314.             \$('#products_sold_unitPriceFob').mask(\"#,##0.00\", {
  6315.                 reverse: true
  6316.             });
  6317.             \$('#products_sold_unitPriceNavlun').mask(\"#,##0.00\", {
  6318.                 reverse: true
  6319.             });
  6320.             \$('#products_sold_totalUnitPrice').mask(\"#,##0.00\", {
  6321.                 reverse: true
  6322.             });
  6323.             \$('#products_sold_totalUnitPurchasePrice').mask(\"#,##0.00\", {
  6324.                 reverse: true
  6325.             });
  6326.             \$('#products_sold_totalPrice').mask(\"#,##0.00\", {
  6327.                 reverse: true
  6328.             });
  6329.             \$('#products_sold_totalPuchasePrice').mask(\"#,##0.00\", {
  6330.                 reverse: true
  6331.             });
  6332.             \$('#sales_form_totalPurchasePrice').mask(\"#,##0.00\", {
  6333.                 reverse: true
  6334.             });
  6335.             \$('#sales_form_totalPurchasePrice').attr('readonly', 'readonly');
  6336.             var totalQuantity = 0;
  6337.             var productId = 0;
  6338.             var productname = \$('#products_sold_productName');
  6339.             var productmeasurement = \$('#products_sold_measurement');
  6340.             var unitPriceFob = \$('#products_sold_unitPriceFob');
  6341.             var unitPricenavlun = \$('#products_sold_unitPriceNavlun');
  6342.             var totalUnitPrice = \$('#products_sold_totalUnitPrice');
  6343.             // ÖDEME FORMU LİSTEYE EKLEME
  6344.             \$('#save-payment-btn').on('click', function() {
  6345.                 let amount = roundToDecimal(convertToDecimal(\$('#payment_amount').val()));
  6346.                 let payment_paymentStatus = \$('#payment_paymentStatus').val();
  6347.                 let payment_paymentDate = \$('#payment_paymentDate').val();
  6348.                 let payment_dueDate = \$('#payment_dueDate').val();
  6349.                 let payment_paymentMethod = \$('#payment_paymentMethod').val();
  6350.                 let payment_description = \$('#payment_description').val();
  6351.                 if (amount <= 0 || !payment_paymentStatus || !payment_paymentDate || !payment_dueDate || !payment_paymentMethod || !payment_description) {
  6352.                     throw new Error(\"Formdaki eksikleri tamamlayın lütfen\")
  6353.                 }
  6354.                 payment = {
  6355.                     uuid: crypto.randomUUID(),
  6356.                     amount: amount,
  6357.                     status: payment_paymentStatus,
  6358.                     paymentDate: payment_paymentDate,
  6359.                     paymentDueDate: payment_dueDate,
  6360.                     paymentMethod: payment_paymentMethod,
  6361.                     description: payment_description,
  6362.                     voucherCode: \$('#payment_voucherCode').val()
  6363.                 }
  6364.                 payments.push(payment);
  6365.                 fetchPaymentForm();
  6366.                 // Trigger update to show AVOIR if needed
  6367.                 fetchSoldListRows();
  6368.             });
  6369.             // Ödeme satırını silme işlemi
  6370.             \$(document).on('click', '.delete-payment', function() {
  6371.                 \$row = \$(this).closest('tr');
  6372.                 let id = \$row.attr(\"id\");
  6373.                 payments = payments.filter(payment => payment.uuid !== id);
  6374.                 fetchPaymentForm();
  6375.                 // Trigger update to remove AVOIR if needed
  6376.                 fetchSoldListRows();
  6377.             });
  6378.             // Ödeme formunu güncelleme
  6379.             function fetchPaymentForm() {
  6380.                 \$('#payment-list-table-tbody').empty();
  6381.                 payments.forEach(function(val) {
  6382.                     var newRow = `<tr id=\"\${val.uuid}\">
  6383.                         <td><input type=\"text\" class=\"form-control payment-amount payment-amount-input\" value=\"\${addCommas(val.amount) || ''}\" name=\"paymentAmount[]\" placeholder=\"Miktar\"></td>
  6384.                         <td>
  6385.                             <select class=\"form-control\" name=\"paymentStatus[]\">
  6386.                                 <option value=\"0\" \${val.status === \"0\" ? 'selected' : ''}>{% trans %} payment_status.paid {% endtrans %}</option>
  6387.                                 <option value=\"1\" \${val.status === \"1\" ? 'selected' : ''}>{% trans %} payment_status.not_paid {% endtrans %}</option>
  6388.                                 <option value=\"2\" \${val.status === \"2\" ? 'selected' : ''}>{% trans %} payment_status.term_sale {% endtrans %}</option>
  6389.                             </select>
  6390.                         </td>
  6391.                         <td><input name=\"paymentDate[]\" type=\"date\" class=\"form-control\" value=\"\${val.paymentDate || ''}\" required></td>
  6392.                         <td><input name=\"paymentDueDate[]\" type=\"date\" class=\"form-control\" value=\"\${val.paymentDueDate || ''}\" required></td>
  6393.                         <td>
  6394.                             <select class=\"form-control\" name=\"paymentMethod[]\">
  6395.                                 <option value=\"0\">Ödeme Yöntemi Seçin</option>
  6396.                                 {% for paymentMethod in paymentMethods %}
  6397.                                 <option value=\"{{ paymentMethod.id }}\" \${val.paymentMethod === '{{ paymentMethod.id }}' ? 'selected' : ''}>
  6398.                                     {{ paymentMethod.name }}
  6399.                                 </option>
  6400.                                 {% endfor %}
  6401.                             </select>
  6402.                         </td>
  6403.                         <td><input type=\"text\" class=\"form-control\" value=\"\${val.description || ''}\" name=\"description[]\">
  6404.                             <input type=\"hidden\" name=\"voucherCode[]\" value=\"\${val.voucherCode || ''}\">
  6405.                         </td>
  6406.                         <td><button type=\"button\" class=\"btn btn-primary btn-sm save-payment-row\">{% trans %} save {% endtrans %}</button></td>
  6407.                         <td><button type=\"button\" class=\"btn btn-danger btn-sm delete-payment\">{% trans %} delete {% endtrans %}</button></td>
  6408.                     </tr>`;
  6409.                     // Yeni satırı tabloya ekle
  6410.                     \$('#payment-list-table-tbody').append(newRow);
  6411.                     \$('#add-payment-modal').modal(\"hide\");
  6412.                     resetPaymentForm();
  6413.                 });
  6414.                 calculateAndWriteDiffBetweenPaymentAndSolds();
  6415.             }
  6416.             function updatePaymentByUUID(uuid, updatedData) {
  6417.                 const paymentIndex = payments.findIndex(payment => payment.uuid === uuid);
  6418.                 if (paymentIndex === -1) {
  6419.                     console.error(`Payment with UUID \${uuid} not found!`);
  6420.                     return false;
  6421.                 }
  6422.                 payments[paymentIndex] = {
  6423.                     ...payments[paymentIndex], // Mevcut veriler
  6424.                     ...updatedData // Yeni veriler
  6425.                 };
  6426.                 fetchPaymentForm();
  6427.                 return true;
  6428.             }
  6429.             function calculateAndWriteDiffBetweenPaymentAndSolds(existingTotals = null) {
  6430.                 const totals = existingTotals || aggregateSoldTotals();
  6431.                 const saleTotalRounded = totals.grandTotalRounded;
  6432.                 const paymentTotal = convertToDecimal(calculateTotalPaymentAmount());
  6433.                 const diff = totals.grandTotal.minus(paymentTotal);
  6434.                 const diffRounded = diff.toDecimalPlaces(2, MONEY_ROUNDING_MODE);
  6435.                 \$('#total-amount-span').html(addCommas(saleTotalRounded.toFixed(2)));
  6436.                 \$('#remainder-amount-span').html(addCommas(diffRounded.toFixed(2)));
  6437.             }
  6438.             function resetPaymentForm() {
  6439.                 \$('#payment_amount').val('');
  6440.                 \$('#payment_description').val('');
  6441.                 \$('#payment_voucherCode').val('');
  6442.                 \$('#payment_voucherCode').closest('.form-group').hide(); // Reset visibility
  6443.             }
  6444.             \$(document).on('click', '.save-payment-row', function() {
  6445.                 const \$row = \$(this).closest('tr');
  6446.                 const uuid = \$row.attr('id');
  6447.                 const updatedData = {
  6448.                     amount: convertToDecimal(\$row.find('input[name=\"paymentAmount[]\"]').val().replace(',', '')).toNumber(),
  6449.                     status: \$row.find('select[name=\"paymentStatus[]\"]').val(),
  6450.                     paymentDate: \$row.find('input[name=\"paymentDate[]\"]').val(),
  6451.                     paymentDueDate: \$row.find('input[name=\"paymentDueDate[]\"]').val(),
  6452.                     paymentMethod: \$row.find('select[name=\"paymentMethod[]\"]').val(),
  6453.                     description: \$row.find('input[name=\"description[]\"]').val(),
  6454.                     voucherCode: \$row.find('input[name=\"voucherCode[]\"]').val()
  6455.                 };
  6456.                 const result = updatePaymentByUUID(uuid, updatedData);
  6457.                 if (result) {
  6458.                     showSuccessAlert(\"Ödeme satırı güncellendi :\", updatedData);
  6459.                 } else {
  6460.                     console.log(\"Failed to update payment.\");
  6461.                 }
  6462.             });
  6463.             function resetAddProductForm() {
  6464.                 \$('#products_sold_quantity').val(0);
  6465.                 \$('#products_sold_totalUnitPurchasePrice').val(0);
  6466.                 \$('#products_sold_unAllocatedQuantity').val(0);
  6467.                 \$('#products_sold_totalPuchasePrice').val(0);
  6468.             }
  6469.             function calculatePrice() {
  6470.                 var quantityP = convertToFloat(\$('#products_sold_quantity').val());
  6471.                 var unAllocatedQuantityP = convertToFloat(\$('#products_sold_unAllocatedQuantity').val());
  6472.                 var totalUnitPurchasePriceP = convertToFloat(\$('#products_sold_totalUnitPurchasePrice').val());
  6473.                 var taxP = convertToFloat(\$('#products_sold_tax').val());
  6474.                 var discountP = convertToFloat(\$('#products_sold_discount').val());
  6475.                 var totalAmount = (quantityP + unAllocatedQuantityP) * totalUnitPurchasePriceP;
  6476.                 var discountedAmount = totalAmount - (totalAmount * (discountP / 100));
  6477.                 var finalAmount = discountedAmount + (discountedAmount * (taxP / 100));
  6478.                 finalAmount = roundToTwoDecimals(finalAmount);
  6479.                 \$('#products_sold_totalPuchasePrice').val(finalAmount);
  6480.             }
  6481.             \$(document).on('change', '#products_sold_tax', calculatePrice);
  6482.             \$(document).on('change', '#products_sold_discount', calculatePrice);
  6483.             \$(document).on('change', '#products_sold_quantity', calculatePrice);
  6484.             \$(document).on('change', '#products_sold_totalUnitPurchasePrice', calculatePrice);
  6485.             function roundToTwoDecimals(number) {
  6486.                 var factor = Math.pow(10, 2);
  6487.                 return (Math.round(number * factor) / factor).toFixed(2);
  6488.             }
  6489.             function validate(s) {
  6490.                 var rgx = /^[0-9]*\\.?[0-9]*\$/;
  6491.                 return s.match(rgx);
  6492.             }
  6493.             function convertToFloat(value) {
  6494.                 if (typeof value === \"string\") {
  6495.                     value = value.replace(',', '');
  6496.                 }
  6497.                 return parseFloat(value);
  6498.             }
  6499.             \$(document).on('change', 'input[name=\"totalUnitPurchasePrice[]\"]', function() {
  6500.                 var unitPrice = \$(this).val();
  6501.             });
  6502.             var productCode = 0;
  6503.             \$('#productselect').on('change', function() {
  6504.                 \$.ajax({
  6505.                     url: \"/stock-detail/\" + \$('#productselect option:selected').val(),
  6506.                     dataType: 'JSON',
  6507.                     method: 'GET',
  6508.                     success: function(response) {
  6509.                         var productid = response.productid;
  6510.                         var product = products.find(function(item) {
  6511.                             return item.productid === productid;
  6512.                         });
  6513.                         product.length = response.length;
  6514.                         product.priceFob = response.priceFob;
  6515.                         product.priceNavlun = response.priceNavlun;
  6516.                         product.totalQuantity = response.totalQuantity;
  6517.                         product.quantity = response.quantity;
  6518.                         product.unAllocatedQuantity = response.unAllocatedQuantity;
  6519.                         product.thickness = response.thickness;
  6520.                         product.totalUnitPrice = response.totalUnitPrice;
  6521.                         product.width = response.width;
  6522.                         selectProduct(product.productid);
  6523.                         getProductCost(product.productid);
  6524.                         fetchStocks();
  6525.                         productname.val(product.name);
  6526.                         productmeasurement.val(product.measurement);
  6527.                         productCode = product.code;
  6528.                         unitPriceFob.val(addCommas(product.priceFob));
  6529.                         unitPricenavlun.val(addCommas(product.priceNavlun));
  6530.                         totalUnitPrice.val(addCommas(product.priceNavlun + response.priceFob));
  6531.                         totalQuantity = product.totalQuantity;
  6532.                         productId = product.productid;
  6533.                         // Seçilen ürün için birimleri yükle ve ana birimi seç
  6534.                         fillUnitSelects(product);
  6535.                         computeAndShowBaseUnitEquivalent();
  6536.                     },
  6537.                     error: function(error) {
  6538.                         // Hata yönetimi
  6539.                     }
  6540.                 });
  6541.             });
  6542.             function isProductService(productId){
  6543.                 const product = products.find(product => product.productid === productId);
  6544.                 const productType = product.productType.key;
  6545.                 if(productType === \"INSTALLATION_SERVICE\" || productType === \"MAINTENANCE_SERVICE\" || productType === \"CONSULTATION_SERVICE\" || productType === 'TREE'){
  6546.                     return true;
  6547.                 }
  6548.                 return false;
  6549.             }
  6550.             // TODO
  6551.             \$('#add-product-row-btn').on('click', function() {
  6552.                 var productId = \$('#productselect').val();
  6553.                 if (!productId || productId <= 0) {
  6554.                     showErrorAlert(\"Ürün seçimi yapın\");
  6555.                     return;
  6556.                 }
  6557.                 let product = getSelectedProduct();
  6558.                 const productType = product.productType.key;
  6559.                 var quantity = \$('#adder-allocated-quantity').val();
  6560.                 var unAllocatedQuantity = \$('#adder-unallocated-quantity').val();
  6561.                 var unitPrice = \$('#adder-price').val();
  6562.                 var tax = \$('#adder-tva-select').val();
  6563.                 var discount = \$('#adder-discount-select').val();
  6564.                 var totalPurchasePrice = \$('#adder-total').val();
  6565.                 quantity = convertToDecimal(quantity);
  6566.                 unAllocatedQuantity = convertToDecimal(unAllocatedQuantity);
  6567.                 unitPrice = convertToDecimal(unitPrice);
  6568.                 tax = convertToDecimal(tax);
  6569.                 discount = convertToDecimal(discount);
  6570.                 totalPurchasePrice = convertToDecimal(totalPurchasePrice);
  6571.                 if(productType === 'TREE') {
  6572.                 }
  6573.                 checkStockQuantity(quantity);
  6574.                 const selectedUnitId = \$('#adder-quantity-unit-select').val();
  6575.                 if (!selectedUnitId || String(selectedUnitId) === '') {
  6576.                     showErrorAlert('Lütfen birim seçiniz.');
  6577.                     return;
  6578.                 }
  6579.                 const item =  addProductToSoldList(
  6580.                                     product.productid,
  6581.                                     product.name,
  6582.                                     product.code,
  6583.                                     product.measurement,
  6584.                                     quantity,
  6585.                                     unitPrice,
  6586.                                     tax,
  6587.                                     discount,
  6588.                                     totalPurchasePrice,
  6589.                                     product.warehouseid,
  6590.                                     unAllocatedQuantity,
  6591.                                     product.thickness,
  6592.                                     product.width,
  6593.                                     product.length,
  6594.                                     product.cost,
  6595.                                     product.productType,
  6596.                                     selectedUnitId,
  6597.                                 );
  6598.                 if(isProductService(product.productid)){
  6599.                     \$('#update_service_id').val(item.uuid);
  6600.                     \$('#updateServiceModal').modal('show');
  6601.                 }else{
  6602.                   if(quantity.toNumber() === 0 && unAllocatedQuantity.toNumber() === 0) {
  6603.                     showErrorAlert(\"Miktar veya tahsis edilmemiş miktar 0 olamaz\");
  6604.                     return;
  6605.                   }
  6606.                 }
  6607.                 fetchSoldListRows();
  6608.                 resetAdderRow();
  6609.             });
  6610.             \$('#service_modal_save_changes_btn').on('click', function() {
  6611.                 const uuid = \$('#update_service_id').val();
  6612.                 const soldProduct = soldList.find(soldProduct => soldProduct.uuid === uuid);
  6613.                 const product  = products.find(product => product.productid === soldProduct.productid);
  6614.                 const productType = product.productType.key;
  6615.                 // Modal değerlerini geri alıp objeye yazıyoruz
  6616.                 soldProduct.productName = \$('#update_service_name').val();
  6617.                 soldProduct.cost = parseFloat(\$('#update_service_cost').val());
  6618.                 soldProduct.description = \$('#update_service_description').val();
  6619.                 const tr = \$('#' + uuid);
  6620.                 console.log(\"Servis güncellendi:\", soldProduct);
  6621.                 \$('#updateServiceModal').modal('hide');
  6622.                 // Rows'ları yeniden render et ki service adı dropdown'da görünsün
  6623.                 fetchSoldListRows();
  6624.                 updateTotalAmounts();
  6625.                 if(isProductService(product.productid)){
  6626.                     addServiceEditButtonIfNeeded(uuid);
  6627.                 }
  6628.             });
  6629.             \$(document).on('click', '.edit-service-button', function () {
  6630.                 const uuid = \$(this).data('uuid');
  6631.                 const soldProduct = soldList.find(sp => sp.uuid === uuid);
  6632.                 \$('#update_service_id').val(uuid);
  6633.                 \$('#update_service_name').val(soldProduct?.productName || \"\");
  6634.                 \$('#update_service_cost').val(soldProduct?.cost || \"0.00\");
  6635.                 \$('#update_service_description').val(soldProduct?.description || \"\");
  6636.                 \$('#updateServiceModal').modal('show');
  6637.             });
  6638.             // TODO:
  6639.             function addServiceEditButtonIfNeeded(uuid) {
  6640.                 const soldProduct = soldList.find(sp => sp.uuid === uuid);
  6641.                 const product = products.find(p => p.productid === soldProduct.productid);
  6642.                 const productType = product.productType.key;
  6643.                 // Sadece ürün service ise buton ekle
  6644.                 if (product && isProductService(product.productid)) {
  6645.                     const tr = \$('#' + uuid);
  6646.                     // Eğer daha önce eklenmediyse ekle
  6647.                     if (tr.find('.edit-service-button').length === 0) {
  6648.                         const btn = `
  6649.                             <button type=\"button\"
  6650.                                     class=\"btn btn-warning btn-sm edit-service-button\"
  6651.                                     data-uuid=\"\${uuid}\"
  6652.                                     title=\"Servisi Güncelle\">
  6653.                                 <i class=\"fas fa-edit\"></i>
  6654.                             </button>`;
  6655.                         // örnek: sil butonunun yanına ekleyelim
  6656.                         tr.find('.btn-group').prepend(btn);
  6657.                     }
  6658.                 }
  6659.             }
  6660.             // Reset adder row form after adding product
  6661.             function resetAdderRow() {
  6662.                 \$('#productselect').val('').trigger('change');
  6663.                 \$('#adder-allocated-quantity').val('0');
  6664.                 \$('#adder-unallocated-quantity').val('0');
  6665.                 \$('#adder-price').val('0');
  6666.                 \$('#adder-discount-select').val('0');
  6667.                 \$('#adder-tva-select').val('0');
  6668.                 \$('#adder-total').val('0');
  6669.                 \$('#unalloc-display').text('0');
  6670.                 clearUnitSelects();
  6671.                 \$('#info-details-content').hide();
  6672.                 \$('#show-info-btn i').removeClass('fa-chevron-up').addClass('fa-info-circle');
  6673.             }
  6674.             // =============================================================================
  6675.             // EVENT HANDLERS FOR SALES LIST EDITING
  6676.             // =============================================================================
  6677.             // Show/hide product info details
  6678.             \$(document).on('click', '.show-row-info-btn', function() {
  6679.                 const \$infoContent = \$(this).closest('tr').next('.info-details-row-class').find('.info-details-content-class');
  6680.                 const \$icon = \$(this).find('i');
  6681.                 if (\$infoContent.is(':visible')) {
  6682.                     \$infoContent.hide();
  6683.                     \$icon.removeClass('fa-chevron-up').addClass('fa-info-circle');
  6684.                     \$(this).closest('tr').next('.info-details-row-class').hide();
  6685.                 } else {
  6686.                     \$infoContent.show();
  6687.                     \$icon.removeClass('fa-info-circle').addClass('fa-chevron-up');
  6688.                     \$(this).closest('tr').next('.info-details-row-class').show();
  6689.                 }
  6690.             });
  6691.             \$(document).on('change', '.product-select-row', function() {
  6692.                 const uuid = \$(this).data('uuid');
  6693.                 const newProductId = parseInt(\$(this).val());
  6694.                 const soldItemIndex = soldList.findIndex(item => item.uuid === uuid);
  6695.                 if (soldItemIndex > -1) {
  6696.                     const newProduct = products.find(p => p.productid === newProductId);
  6697.                     if (newProduct) {
  6698.                         soldList[soldItemIndex].productid = newProduct.productid;
  6699.                         soldList[soldItemIndex].productName = newProduct.name;
  6700.                         soldList[soldItemIndex].code = newProduct.code;
  6701.                         soldList[soldItemIndex].measurement = newProduct.measurement;
  6702.                         soldList[soldItemIndex].cost = newProduct.cost;
  6703.                     }
  6704.                     fetchSoldListRows();
  6705.                     updateTotalAmounts();
  6706.                 }
  6707.                 console.table(soldList);
  6708.             });
  6709.             // Handle unit price changes in sold list rows
  6710.             \$(document).on('input change', '.price-input-row', function() {
  6711.                 const uuid = \$(this).data('uuid');
  6712.                 const value = \$(this).val();
  6713.                 // Birim fiyat manuel değiştirildi, artık otomatik hesaplama yapılmalı
  6714.                 delete rowHasManualTotal[uuid];
  6715.                 updateSoldListItem(uuid, 'unitPrice', value);
  6716.             });
  6717.             // Handle discount changes in sold list rows
  6718.             \$(document).on('change', '.discount-select-row', function() {
  6719.                 const uuid = \$(this).data('uuid');
  6720.                 const value = \$(this).val();
  6721.                 // İndirim değiştirildi, artık otomatik hesaplama yapılmalı
  6722.                 delete rowHasManualTotal[uuid];
  6723.                 updateSoldListItem(uuid, 'discount', value);
  6724.             });
  6725.             // Handle tax changes in sold list rows
  6726.             \$(document).on('change', '.tax-select-row', function() {
  6727.                 const uuid = \$(this).data('uuid');
  6728.                 const value = \$(this).val();
  6729.                 // KDV değiştirildi, artık otomatik hesaplama yapılmalı
  6730.                 delete rowHasManualTotal[uuid];
  6731.                 updateSoldListItem(uuid, 'tax', value);
  6732.             });
  6733.             // Handle unit selection changes in sold list rows
  6734.             \$(document).on('change', '.quantity-unit-select', function() {
  6735.                 const uuid = \$(this).data('uuid');
  6736.                 const unitId = \$(this).val();
  6737.                 const \$quantityInput = \$(`.quantity-input-row[data-uuid=\"\${uuid}\"]`);
  6738.                 const currentQuantity = parseFloat(\$quantityInput.val()) || 0;
  6739.                 // Update the selected unit in sold list
  6740.                 const itemIndex = soldList.findIndex(item => item.uuid === uuid);
  6741.                 if (itemIndex !== -1) {
  6742.                     const item = soldList[itemIndex];
  6743.                     const oldUnitId = item.selectedUnitId;
  6744.                     item.selectedUnitId = unitId;
  6745.                     // Show unit conversion equivalent
  6746.                     showUnitConversionForRow(uuid, item.productid, currentQuantity, unitId);
  6747.                     // If changing from one unit to another, convert the quantity
  6748.                     if (oldUnitId && oldUnitId !== unitId && unitId && currentQuantity > 0) {
  6749.                         convertQuantityBetweenUnits(item.productid, currentQuantity, oldUnitId, unitId, function(convertedQuantity) {
  6750.                             if (convertedQuantity !== null) {
  6751.                                 \$quantityInput.val(convertedQuantity.toFixed(2));
  6752.                                 updateSoldListItem(uuid, 'quantity', convertedQuantity);
  6753.                                 // Update conversion display with new quantity
  6754.                                 showUnitConversionForRow(uuid, item.productid, convertedQuantity, unitId);
  6755.                             }
  6756.                         });
  6757.                     }
  6758.                     // Recompute and store base unit quantity for the row
  6759.                     computeBaseUnitQuantity(item.productid, unitId, parseFloat(\$quantityInput.val()) || 0, function(baseQty){
  6760.                         const idx = soldList.findIndex(sp => sp.uuid === uuid);
  6761.                         if(idx !== -1){ soldList[idx].baseUnitQuantity = convertToDecimal(baseQty || 0).toNumber(); }
  6762.                     });
  6763.                 }
  6764.             });
  6765.             // Handle quantity changes in sold list rows to update conversion display
  6766.             \$(document).on('input change', '.quantity-input-row', function() {
  6767.                 const uuid = \$(this).data('uuid');
  6768.                 const value = \$(this).val();
  6769.                 const item = soldList.find(item => item.uuid === uuid);
  6770.                 if (item && item.selectedUnitId) {
  6771.                     showUnitConversionForRow(uuid, item.productid, parseFloat(value) || 0, item.selectedUnitId);
  6772.                 }
  6773.                 // Miktar manuel değiştirildi, artık otomatik hesaplama yapılmalı
  6774.                 delete rowHasManualTotal[uuid];
  6775.                 updateSoldListItem(uuid, 'quantity', value);
  6776.                 // Also refresh baseUnitQuantity on quantity change
  6777.                 if (item) {
  6778.                     computeBaseUnitQuantity(item.productid, item.selectedUnitId, parseFloat(value) || 0, function(baseQty){
  6779.                         const idx = soldList.findIndex(sp => sp.uuid === uuid);
  6780.                         if(idx !== -1){ soldList[idx].baseUnitQuantity = convertToDecimal(baseQty || 0).toNumber(); }
  6781.                     });
  6782.                 }
  6783.             });
  6784.             // Show unit conversion equivalent for a specific row
  6785.             function showUnitConversionForRow(uuid, productId, quantity, fromUnitId) {
  6786.                 if (!fromUnitId || !quantity || quantity <= 0) {
  6787.                     updateRowQuantityHint(uuid, '');
  6788.                     return;
  6789.                 }
  6790.                 const product = products.find(p => p.productid === productId);
  6791.                 if (!product || !product.measurementUnitId) {
  6792.                     updateRowQuantityHint(uuid, '');
  6793.                     return;
  6794.                 }
  6795.                 // If already in product's main unit, no conversion needed
  6796.                 if (fromUnitId == product.measurementUnitId) {
  6797.                     updateRowQuantityHint(uuid, '');
  6798.                     return;
  6799.                 }
  6800.                 \$.ajax({
  6801.                     url: '/admin/measurement/convert-to-product-unit',
  6802.                     method: 'POST',
  6803.                     dataType: 'json',
  6804.                     data: {
  6805.                         productId: productId,
  6806.                         fromUnitId: fromUnitId,
  6807.                         quantity: quantity
  6808.                     },
  6809.                     success: function(resp) {
  6810.                         if (resp && resp.success) {
  6811.                             const unitText = product.measurementUnit ? (' ' + product.measurementUnit) : '';
  6812.                             updateRowQuantityHint(uuid, (Number(resp.result).toFixed(2)) + unitText);
  6813.                 } else {
  6814.                             updateRowQuantityHint(uuid, '');
  6815.                         }
  6816.                     },
  6817.                     error: function() {
  6818.                         updateRowQuantityHint(uuid, '');
  6819.                     }
  6820.                 });
  6821.             }
  6822.             // Update quantity hint for a specific row
  6823.             function updateRowQuantityHint(uuid, text) {
  6824.                 let \$hint = \$(`.quantity-conversion-hint[data-uuid=\"\${uuid}\"]`);
  6825.                 if (\$hint.length === 0) {
  6826.                     const \$quantityCell = \$(`.quantity-input-row[data-uuid=\"\${uuid}\"]`).closest('td');
  6827.                     \$quantityCell.append(`<small class=\"form-text text-muted quantity-conversion-hint\" data-uuid=\"\${uuid}\"></small>`);
  6828.                     \$hint = \$(`.quantity-conversion-hint[data-uuid=\"\${uuid}\"]`);
  6829.                 }
  6830.                 \$hint.text(text || '');
  6831.             }
  6832.             // Convert quantity between different measurement units
  6833.             function convertQuantityBetweenUnits(productId, quantity, fromUnitId, toUnitId, callback) {
  6834.                 if (!fromUnitId || !toUnitId || fromUnitId === toUnitId) {
  6835.                     callback(quantity);
  6836.                     return;
  6837.                 }
  6838.                 \$.ajax({
  6839.                     url: '/admin/measurement/convert-between-units',
  6840.                     method: 'POST',
  6841.                     dataType: 'json',
  6842.                     data: {
  6843.                         productId: productId,
  6844.                         fromUnitId: fromUnitId,
  6845.                         toUnitId: toUnitId,
  6846.                         quantity: quantity
  6847.                     },
  6848.                     success: function(resp) {
  6849.                         if (resp && resp.success) {
  6850.                             callback(parseFloat(resp.result));
  6851.                 } else {
  6852.                             console.error('Unit conversion failed:', resp);
  6853.                             callback(null);
  6854.                         }
  6855.                     },
  6856.                     error: function() {
  6857.                         console.error('Unit conversion request failed');
  6858.                         callback(null);
  6859.                     }
  6860.                 });
  6861.             }
  6862.             // Handle total price changes (reverse calculation to unit price)
  6863.             \$(document).on('change blur', '.total-input-row', function() {
  6864.                 updateUnitPriceFromTotal(\$(this).data('uuid'));
  6865.             });
  6866.             // Handle delete row button clicks
  6867.             const currencySymbol = \"{{ 'currency.symbol'|trans|e('js') }}\";
  6868.             const PAYMENT_TOLERANCE = 0.01;
  6869.             const AUTO_PAYMENT_DESCRIPTION = 'Sistem tarafından ödeme otomatik oluşturuldu';
  6870.             const AUTO_PAYMENT_STATUS_TEXT = 'Ödendi';
  6871.             let autoPaymentModalState = null;
  6872.             let cachedCashPaymentMethod = null;
  6873.             function detectCashPaymentMethod() {
  6874.                 const \$options = \$('#payment_paymentMethod option');
  6875.                 let fallback = null;
  6876.                 let cashCandidate = null;
  6877.                 \$options.each(function() {
  6878.                     const \$option = \$(this);
  6879.                     const value = (\$option.val() || '').trim();
  6880.                     if (!value) {
  6881.                         return;
  6882.                     }
  6883.                     if (!fallback) {
  6884.                         fallback = { id: value, label: (\$option.text() || '').trim() };
  6885.                     }
  6886.                     const label = (\$option.text() || '').toLowerCase();
  6887.                     if (label.includes('cash') || label.includes('nakit')) {
  6888.                         cashCandidate = { id: value, label: (\$option.text() || '').trim() };
  6889.                         return false;
  6890.                     }
  6891.                 });
  6892.                 if (cashCandidate) {
  6893.                     return cashCandidate;
  6894.                 }
  6895.                 if (fallback) {
  6896.                     return fallback;
  6897.                 }
  6898.                 return { id: '1', label: 'Cash' };
  6899.             }
  6900.             function ensureCashPaymentMethod() {
  6901.                 if (!cachedCashPaymentMethod) {
  6902.                     cachedCashPaymentMethod = detectCashPaymentMethod();
  6903.                 }
  6904.                 return cachedCashPaymentMethod;
  6905.             }
  6906.             function normalizeCurrency(value) {
  6907.                 return convertToDecimal(value).toDecimalPlaces(2, Decimal.ROUND_HALF_UP).toNumber();
  6908.             }
  6909.             function formatCurrency(value) {
  6910.                 const normalized = normalizeCurrency(value);
  6911.                 const formatted = addCommas(normalized.toFixed(2));
  6912.                 return formatted.replace(/,/g, '#').replace(/\\./g, ',').replace(/#/g, '.') + ' ' + currencySymbol;
  6913.             }
  6914.             function calculateTotalPaymentAmount() {
  6915.                 let total = new Decimal(0);
  6916.                 payments.forEach(function(payment) {
  6917.                     total = total.plus(convertToDecimal(payment.amount));
  6918.                 });
  6919.                 return total.toNumber();
  6920.             }
  6921.             function getSaleDateValue() {
  6922.                 const saleDate = \$('#sales_form_salesDate').val();
  6923.                 if (saleDate && saleDate.trim() !== '') {
  6924.                     return saleDate;
  6925.                 }
  6926.                 return new Date().toISOString().split('T')[0];
  6927.             }
  6928.             function createAutoPaymentPayload(amount, saleDate) {
  6929.                 const method = ensureCashPaymentMethod();
  6930.                 return {
  6931.                     uuid: crypto.randomUUID(),
  6932.                     amount: normalizeCurrency(amount),
  6933.                     status: '0',
  6934.                     paymentDate: saleDate,
  6935.                     paymentDueDate: saleDate,
  6936.                     paymentMethod: method.id,
  6937.                     description: AUTO_PAYMENT_DESCRIPTION
  6938.                 };
  6939.             }
  6940.             function openAutoPaymentModal(config) {
  6941.                 autoPaymentModalState = {
  6942.                     scenario: config.scenario,
  6943.                     amount: normalizeCurrency(config.amount),
  6944.                     saleDate: config.saleDate,
  6945.                     saleTotal: normalizeCurrency(config.saleTotal),
  6946.                     currentPayments: normalizeCurrency(config.currentPayments)
  6947.                 };
  6948.                 const method = ensureCashPaymentMethod();
  6949.                 let message = '';
  6950.                 if (config.scenario === 'no-payment') {
  6951.                     message = 'Bu satış için henüz ödeme girilmedi. Aşağıdaki bilgilerle otomatik bir nakit ödeme oluşturulacaktır.';
  6952.                 } else {
  6953.                     message = 'Girilen ödemeler satış toplamı ile uyumsuz. Eksik tutar otomatik bir nakit ödeme olarak eklenecektir.';
  6954.                 }
  6955.                 \$('#auto-payment-message').text(message);
  6956.                 \$('#auto-payment-sale-total').text(formatCurrency(autoPaymentModalState.saleTotal));
  6957.                 \$('#auto-payment-current-payments').text(formatCurrency(autoPaymentModalState.currentPayments));
  6958.                 \$('#auto-payment-amount').text(formatCurrency(autoPaymentModalState.amount));
  6959.                 \$('#auto-payment-method').text(method.label);
  6960.                 \$('#auto-payment-status').text(AUTO_PAYMENT_STATUS_TEXT);
  6961.                 \$('#auto-payment-description').text(AUTO_PAYMENT_DESCRIPTION);
  6962.                 \$('#confirm-auto-payment').prop('disabled', false);
  6963.                 \$('#autoPaymentModal').modal('show');
  6964.             }
  6965.             function validateSalesForm() {
  6966.                 const form = \$('form[name=\"sales_form\"]');
  6967.                 if (!form || form.length === 0) {
  6968.                     return true;
  6969.                 }
  6970.                 return form[0].reportValidity();
  6971.             }
  6972.             function submitSalesRequest() {
  6973.                 if (!validateSalesForm()) {
  6974.                     return;
  6975.                 }
  6976.                 const salesData = {
  6977.                     payments: payments,
  6978.                     soldList: soldList,
  6979.                     invoice: {
  6980.                         invoiceNumber: \$('#sales_form_invoiceNumber').val(),
  6981.                         customer: \$('#sales_form_customer').val(),
  6982.                         paymentStatus: \$('#sales_form_paymentStatus').val(),
  6983.                         salesDate: \$('#sales_form_salesDate').val(),
  6984.                         deliveryDate: \$('#sales_form_deliveryDate').val(),
  6985.                         dueDate: \$('#sales_form_dueDate').val(),
  6986.                         validDate: \$('#sales_form_validDate').val(),
  6987.                         seller: \$('#sales_form_seller').val(),
  6988.                         description: \$('#sales_form_description').val(),
  6989.                         shippingNotes: \$('#sales_form_shippingNotes').val(),
  6990.                         paymentNotes: \$('#sales_form_paymentNotes').val(),
  6991.                         salesType: \$('input[name=\"salesType\"]').filter(':checked').val() || 'proforma',
  6992.                         salesStatus: \$('#sales_form_status').val() ? \$('#sales_form_status').val() : '0'
  6993.                     }
  6994.                 };
  6995.                 \$.ajax({
  6996.                     url: \"{{ path('app_admin_sales_create') }}\",
  6997.                     method: 'POST',
  6998.                     data: salesData,
  6999.                     success: function(response) {
  7000.                         window.location.href = \"/sales/detail/\" + response.id;
  7001.                         Swal.fire({
  7002.                             icon: 'success',
  7003.                             title: 'Başarılı',
  7004.                             text: 'Satış başarıyla oluşturuldu'
  7005.                         });
  7006.                     },
  7007.                     error: function(xhr) {
  7008.                         var response = JSON.parse(xhr.responseText);
  7009.                         showErrorAlert(response.message);
  7010.                     }
  7011.                 });
  7012.             }
  7013.             function finalizeSalesSubmission() {
  7014.                 const saleTotal = convertToDecimal(getTotalSoldAmount());
  7015.                 const totalPayments = convertToDecimal(calculateTotalPaymentAmount());
  7016.                 const difference = saleTotal.minus(totalPayments).abs().toNumber();
  7017.                 if (difference > PAYMENT_TOLERANCE) {
  7018.                     showErrorAlert('Ödemeler satış toplamı ile hâlâ uyumsuz. Lütfen kontrol edin.');
  7019.                     return;
  7020.                 }
  7021.                 submitSalesRequest();
  7022.             }
  7023.             \$('#confirm-auto-payment').on('click', function() {
  7024.                 if (!autoPaymentModalState) {
  7025.                     return;
  7026.                 }
  7027.                 const saleDate = autoPaymentModalState.saleDate || getSaleDateValue();
  7028.                 const autoPayment = createAutoPaymentPayload(autoPaymentModalState.amount, saleDate);
  7029.                 payments.push(autoPayment);
  7030.                 fetchPaymentForm();
  7031.                 calculateAndWriteDiffBetweenPaymentAndSolds();
  7032.                 \$('#confirm-auto-payment').prop('disabled', true);
  7033.                 \$('#autoPaymentModal').modal('hide');
  7034.                 autoPaymentModalState = null;
  7035.                 finalizeSalesSubmission();
  7036.             });
  7037.             \$('#autoPaymentModal').on('hidden.bs.modal', function() {
  7038.                 \$('#confirm-auto-payment').prop('disabled', false);
  7039.                 autoPaymentModalState = null;
  7040.             });
  7041.             ensureCashPaymentMethod();
  7042.             \$(document).on('click', '.delete-row-button', function() {
  7043.                 const uuid = \$(this).data('uuid');
  7044.                 deleteProductInSoldList(uuid);
  7045.                 \$(`tr[id=\"\${uuid}\"]`).remove();
  7046.                 \$(`.info-details-row-class[data-uuid=\"\${uuid}\"]`).remove();
  7047.                 fetchStocks();
  7048.                 updateTotalAmounts();
  7049.                 fetchPaymentForm();
  7050.                 \$('#sales_form_totalPurchasePrice').val(addCommas(getTotalSoldAmount()));
  7051.             });
  7052.              // Handle unallocated quantity modal for rows
  7053.             \$(document).on('click', '.open-unallocated-modal-row', function() {
  7054.                 const uuid = \$(this).data('uuid');
  7055.                 const itemIndex = soldList.findIndex(item => item.uuid === uuid);
  7056.                 if (itemIndex === -1) return;
  7057.                 // Değeri gizli input yerine doğrudan soldList'ten oku
  7058.                 const currentQty = soldList[itemIndex].unAllocatedQuantity || 0;
  7059.                 \$('#modal-unallocated-quantity').val(Number(currentQty).toFixed(2));
  7060.                 // Store current uuid for saving later
  7061.                 \$('#unallocatedModal').data('current-uuid', uuid);
  7062.                 \$('#unallocatedModal').modal('show');
  7063.             });
  7064.             // Save unallocated quantity from modal for rows
  7065.             \$(document).on('click', '#save-unallocated-btn', function() {
  7066.                  const uuid = \$('#unallocatedModal').data('current-uuid');
  7067.                     // Sadece satırlar için olan bölüm (uuid varsa)
  7068.                     if (uuid) {
  7069.                         const qty = \$('#modal-unallocated-quantity').val() || 0;
  7070.                         const newUnallocatedQty = convertToDecimal(qty).toNumber();
  7071.                         // 1. soldList'teki ilgili ürünü bul ve unAllocatedQuantity'yi güncelle
  7072.                         const itemIndex = soldList.findIndex(item => item.uuid === uuid);
  7073.                         if (itemIndex > -1) {
  7074.                             soldList[itemIndex].unAllocatedQuantity = newUnallocatedQty;
  7075.                         }
  7076.                         // 2. DOĞRU SATIRI HEDEFLEYEREK butondaki sayıyı güncelle
  7077.                         const \$button = \$(`.open-unallocated-modal-row[data-uuid=\"\${uuid}\"]`);
  7078.                         \$button.find('.unalloc-display').text(newUnallocatedQty.toFixed(2));
  7079.                         // 3. Tahsis edilmemiş miktar değiştirildi, artık otomatik hesaplama yapılmalı
  7080.                         delete rowHasManualTotal[uuid];
  7081.                         // 4. Satırın genel toplamlarını ve stokları güncelle
  7082.                         updateSoldProductFromRow(uuid);
  7083.                         \$('#unallocatedModal').modal('hide');
  7084.                     } else { // Bu kısım adder-row için, dokunmuyoruz
  7085.                         const qty = \$('#modal-unallocated-quantity').val() || 0;
  7086.                         \$('#adder-unallocated-quantity').val(qty).trigger('change');
  7087.                         \$('#unalloc-display').text(qty);
  7088.                         onInputChange.call(\$('#adder-unallocated-quantity')[0]);
  7089.                         \$('#unallocatedModal').modal('hide');
  7090.                     }
  7091.                             });
  7092.             // Flag to prevent circular updates between unit price and total
  7093.             let isUpdatingFromTotal = false;
  7094.             let isUpdatingFromUnitPrice = false;
  7095.             // adder-row input alanlarının değişikliklerini dinleme
  7096.             \$('#adder-row').on('input change',
  7097.                 '#adder-allocated-quantity, ' +
  7098.                 '#adder-unallocated-quantity, ' +
  7099.                 '#adder-price, ' +
  7100.                 '#adder-discount-select, ' +
  7101.                 '#adder-tva-select, ' +
  7102.                 '#adder-total', onInputChange);
  7103.             // Birim dönüşümünü yazma bittiğinde (blur) ve birim seçiminde (change) yap
  7104.             \$('#adder-row').on('blur', '#adder-allocated-quantity', function(){
  7105.                 computeAndShowBaseUnitEquivalent();
  7106.             });
  7107.             \$('#adder-row').on('change', '#adder-quantity-unit-select', function(){
  7108.                 computeAndShowBaseUnitEquivalent();
  7109.             });
  7110.             // Adder rowdaki input alanlarının değişikliklerini dinleme
  7111.             function onInputChange() {
  7112.                 if(\$(this).attr('id') === 'adder-total') {
  7113.                     // Toplam manuel değiştirildi → birim fiyatı hesapla, ama toplamı tekrar değiştirme
  7114.                     if(isUpdatingFromUnitPrice) return;
  7115.                     isUpdatingFromTotal = true;
  7116.                     const totalAmount = convertToDecimal(\$('#adder-total').val() || 0).toNumber();
  7117.                     const allocatedQuantity = convertToDecimal(\$('#adder-allocated-quantity').val() || 0).toNumber();
  7118.                     const unallocatedQuantity = convertToDecimal(\$('#adder-unallocated-quantity').val() || 0).toNumber();
  7119.                     const discountPercentage = convertToDecimal(((\$('#adder-discount-select').val() || '0') + '').replace('%', '')).toNumber();
  7120.                     const tvaPercentage = convertToDecimal(((\$('#adder-tva-select').val() || '0') + '').replace('%', '')).toNumber();
  7121.                     const unitPrice = calculateUnitPrice(totalAmount, allocatedQuantity, unallocatedQuantity, tvaPercentage, discountPercentage);
  7122.                     \$('#adder-price').val(convertToDecimal(unitPrice).toDecimalPlaces(2, MONEY_ROUNDING_MODE).toFixed(2));
  7123.                     setTimeout(function(){ isUpdatingFromTotal = false; }, 0);
  7124.                 } else {
  7125.                     // Birim fiyat, miktar, indirim veya KDV değişti → toplamı hesapla
  7126.                     if(isUpdatingFromTotal) return;
  7127.                     isUpdatingFromUnitPrice = true;
  7128.                     const allocatedQuantity = convertToDecimal(\$('#adder-allocated-quantity').val() || 0).toNumber();
  7129.                     const unallocatedQuantity = convertToDecimal(\$('#adder-unallocated-quantity').val() || 0).toNumber();
  7130.                     const price = convertToDecimal(\$('#adder-price').val() || 0).toNumber();
  7131.                     const discountPercentage = convertToDecimal(((\$('#adder-discount-select').val() || '0') + '').replace('%', '')).toNumber();
  7132.                     const tvaPercentage = convertToDecimal(((\$('#adder-tva-select').val() || '0') + '').replace('%', '')).toNumber();
  7133.                     calculateTotal(allocatedQuantity, unallocatedQuantity, price, tvaPercentage, discountPercentage);
  7134.                     setTimeout(function(){ isUpdatingFromUnitPrice = false; }, 0);
  7135.                 }
  7136.             }
  7137.             function roundToNearestCent(amount) {
  7138.                 return Math.round(amount * 100) / 100;
  7139.             }
  7140.             // Toplam tutarı hesaplama
  7141.             // Her ara adımda virgülden sonra 2 hane gösterilecek, 3. hane 5 ve üzeri ise yukarı yuvarlanacak
  7142.             function calculateTotal(allocatedQuantity, unallocatedQuantity, price, tvaPercentage, discountPercentage) {
  7143.                 const totals = calculateRowFinancials({
  7144.                     quantity: allocatedQuantity,
  7145.                     unAllocatedQuantity: unallocatedQuantity,
  7146.                     unitPrice: price,
  7147.                     discount: discountPercentage,
  7148.                     tax: tvaPercentage
  7149.                 });
  7150.                 \$('#adder-total').val(totals.totalRounded.toFixed(2));
  7151.             }
  7152.             // Toplam tutardan Birim fiyatı hesaplama
  7153.             function calculateUnitPrice(totalAmount, allocatedQuantity, unallocatedQuantity, tvaPercentage, discountPercentage) {
  7154.                 const totalQuantity = convertToDecimal(allocatedQuantity || 0).plus(convertToDecimal(unallocatedQuantity || 0));
  7155.                 if (totalQuantity.isZero()) {
  7156.                     return 0;
  7157.                 }
  7158.                 const total = convertToDecimal(totalAmount || 0);
  7159.                 // Eğer toplam 0 ise, birim fiyat da 0 olmalı
  7160.                 if (total.isZero()) {
  7161.                     return 0;
  7162.                 }
  7163.                 const discountMultiplier = new Decimal(1).minus(convertToDecimal(discountPercentage || 0).div(100));
  7164.                 const taxMultiplier = new Decimal(1).plus(convertToDecimal(tvaPercentage || 0).div(100));
  7165.                 // %100 indirimde discountMultiplier = 0 olur, bu durumda birim fiyat hesaplanamaz
  7166.                 // Çünkü total = (unitPrice * quantity * (1 - discount) * (1 + tax))
  7167.                 // discount = 100% ise, unitPrice = 0 olmalı (ya da sonsuz, ama mantıklı olan 0)
  7168.                 if (discountMultiplier.isZero()) {
  7169.                     return 0;
  7170.                 }
  7171.                 if (taxMultiplier.isZero()) {
  7172.                     return 0;
  7173.                 }
  7174.                 // Formül: unitPrice = total / (quantity * (1 - discount%) * (1 + tax%))
  7175.                 const subtotal = total.div(taxMultiplier).div(discountMultiplier);
  7176.                 const unitPrice = subtotal.div(totalQuantity);
  7177.                 return unitPrice.toDecimalPlaces(6, MONEY_ROUNDING_MODE).toNumber();
  7178.             }
  7179.             function getProductCost(pid) {
  7180.                 // Popup için URL burada oluşturuluyor.
  7181.                 const url = '/product-cost/' + pid + '/' + getSelectedProduct().warehouseid;
  7182.                 \$.ajax({
  7183.                     url: \"/product-cost-detail/\" + pid + '?warehouse=' + getSelectedProduct().warehouseid,
  7184.                     method: \"POST\",
  7185.                     dataType: \"JSON\",
  7186.                     success: function(data) {
  7187.                         var product = getSelectedProduct();
  7188.                         product.cost = data.cost;
  7189.                         product.measurementUnit = data.measurement;
  7190.                         \$('.stock-info-span').html(data.stock.toFixed(2).toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, \",\") + \" \" + data.measurement);
  7191.                         \$('.cost-info-span').html(data.cost.toFixed(2).toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, \",\") + \" €\"); // Eski detay butonu kaldırıldı
  7192.                         \$('.measurement-unit-info-span').html(data.measurement);
  7193.                         \$('#hidden-cost-input').val(data.cost);
  7194.                         // \"Maliyet\" popup açıyor maliyet detaylarını gösteriyor.
  7195.                         const detailsHtml = `
  7196.                             <div class=\"row align-items-center\">
  7197.                                 <div class=\"col-md-3\">\${product.name}</div>
  7198.                                 <div class=\"col-md-3\">
  7199.                                     <strong>
  7200.                                         <button type=\"button\" class=\"btn btn-link btn-sm p-0 cost-popup-btn\" data-url=\"\${url}\">Maliyet: \${data.cost.toFixed(2)} €</button>
  7201.                                     </strong>
  7202.                                 </div>
  7203.                                 <div class=\"col-md-3\"><strong>Stok:</strong> \${data.stock.toFixed(2)} \${data.measurement}</div>
  7204.                                 <div class=\"col-md-3\"><strong>Birim:</strong> \${data.measurement}</div>
  7205.                             </div>
  7206.                         `;
  7207.                         \$('#info-details-content').html(detailsHtml);
  7208.                         return data;
  7209.                     },
  7210.                     error: function(data) {
  7211.                         \$('#info-details-content').html('<div class=\"text-danger\">Ürün maliyet bilgileri yüklenemedi.</div>');
  7212.                     }
  7213.                 });
  7214.             }
  7215.             \$(document).on('click', '.cost-popup-btn', function() {
  7216.                 const url = \$(this).data('url');
  7217.                 if (url) {
  7218.                     createPopup(url, 'cost-detail-window');
  7219.                 }
  7220.             });
  7221.             // Unallocated modal açıldığında mask'i uygula
  7222.             \$('#unallocatedModal').on('shown.bs.modal', function() {
  7223.                 applyMasks();
  7224.             });
  7225.             // Unallocated modal aç/kapat ve değerleri senkronize et
  7226.             \$(document).on('click', '#open-unallocated-modal', function() {
  7227.                 // Mevcut değerleri moda aktarma
  7228.                 const currentQty = \$('#adder-unallocated-quantity').val() || 0;
  7229.                 const currentUnit = \$('#adder-unallocated-quantity-unit-select').val() || '';
  7230.                 \$('#modal-unallocated-quantity').val(Number(currentQty).toFixed(2));
  7231.                 // Seçili ürünün saklanan birimlerini modal select'ine doldur
  7232.                 const selectedProduct = getSelectedProduct();
  7233.                 if (selectedProduct && selectedProduct.convertibleUnits) {
  7234.                     populateSelectWithUnits(\$('#modal-unallocated-unit'), selectedProduct.convertibleUnits);
  7235.                 } else {
  7236.                     \$('#modal-unallocated-unit').empty().append('<option value=\"\">-</option>');
  7237.                 }
  7238.                 \$('#modal-unallocated-unit').val(currentUnit);
  7239.                 \$('#unallocatedModal').modal('show');
  7240.             });
  7241.             // 'Tahsis Edilmemiş Miktar' Modal'ındaki Kaydet Butonunun Düzeltilmiş Hali
  7242.             \$(document).on('click', '#save-unallocated-btn', function() {
  7243.                 const uuid = \$('#unallocatedModal').data('current-uuid');
  7244.                 const qty = \$('#modal-unallocated-quantity').val() || 0;
  7245.                 const newUnallocatedQty = convertToDecimal(qty).toNumber();
  7246.                 // DURUM 1: Satış listesindeki bir satır güncelleniyor (uuid mevcut)
  7247.                 if (uuid) {
  7248.                     // 1. soldList'teki ilgili ürünü bul ve unAllocatedQuantity'yi güncelle
  7249.                     const itemIndex = soldList.findIndex(item => item.uuid === uuid);
  7250.                     if (itemIndex > -1) {
  7251.                         soldList[itemIndex].unAllocatedQuantity = newUnallocatedQty;
  7252.                     }
  7253.                     // 2. Sadece ilgili satırı ID ile hedefle ve içindeki göstergeyi güncelle
  7254.                     const \$row = \$(`#\${uuid}`);
  7255.                     \$row.find('.unalloc-display').text(newUnallocatedQty.toFixed(2));
  7256.                     // 3. Satırın genel toplamlarını ve stokları güncelle
  7257.                     updateSoldProductFromRow(uuid);
  7258.                 }
  7259.                 // DURUM 2: Adder-row (ekleme satırı) güncelleniyor (uuid mevcut değil)
  7260.                 else {
  7261.                     // Sadece adder-row'daki gizli input'u ve göstergeyi güncelle
  7262.                     \$('#adder-unallocated-quantity').val(newUnallocatedQty).trigger('change');
  7263.                     \$('#unalloc-display').text(newUnallocatedQty.toFixed(2));
  7264.                     // Adder-row'daki toplamı yeniden hesapla
  7265.                     onInputChange.call(\$('#adder-unallocated-quantity')[0]);
  7266.                 }
  7267.                 // İşlem tamamlandıktan sonra modalı kapat
  7268.                 \$('#unallocatedModal').modal('hide');
  7269.                 // Modal'daki uuid verisini temizle ki bir sonraki açılışta karışmasın
  7270.                 \$('#unallocatedModal').removeData('current-uuid');
  7271.             });
  7272.             function formatState(state) {
  7273.                 if (!state.id) {
  7274.                     return state.text;
  7275.                 }
  7276.                 var baseUrl = \"/images\";
  7277.                 var \$state = \$(
  7278.                     '<span><img src=\"' + baseUrl + '/' + state.element.dataset.image + '\" class=\"img-flag list-image\" style=\"width: 50px;\"/> ' + state.text + '</span>'
  7279.                 );
  7280.                 return \$state;
  7281.             };
  7282.             \$('#productselect').select2({
  7283.                 theme: 'bootstrap4',
  7284.                 dropdownCssClass: 'custom-select-dropdown',
  7285.                 placeholder: 'Ürün Seçin',
  7286.                 allowClear: true
  7287.             });
  7288.             function showErrorAlert(message) {
  7289.                 Swal.fire({
  7290.                     icon: 'error',
  7291.                     title: 'Oops...',
  7292.                     text: '' + message,
  7293.                     background: 'white',
  7294.                 });
  7295.             }
  7296.             window.addEventListener(\"error\", function(event) {
  7297.                 showErrorAlert(event.message);
  7298.             });
  7299.             function showSuccessAlert(message) {
  7300.                 Swal.fire({
  7301.                     icon: 'success',
  7302.                     title: 'Başarılı',
  7303.                     text: '' + message,
  7304.                     background: 'white',
  7305.                 });
  7306.             }
  7307.             \$('#submitbtn').on('click', function(event) {
  7308.                 event.preventDefault();
  7309.                 if (soldList.length === 0) {
  7310.                     showErrorAlert(\"{% trans %} sale.errors.cannot_save_without_products {% endtrans %}\");
  7311.                     return;
  7312.                 }
  7313.                 if (!validateSalesForm()) {
  7314.                     return;
  7315.                 }
  7316.                 const saleTotalValue = convertToDecimal(getTotalSoldAmount()).toNumber();
  7317.                 const currentPaymentTotal = convertToDecimal(calculateTotalPaymentAmount()).toNumber();
  7318.                 const saleDate = getSaleDateValue();
  7319.                 if (payments.length === 0 && saleTotalValue > PAYMENT_TOLERANCE) {
  7320.                     openAutoPaymentModal({
  7321.                         scenario: 'no-payment',
  7322.                         amount: saleTotalValue,
  7323.                         saleTotal: saleTotalValue,
  7324.                         currentPayments: currentPaymentTotal,
  7325.                         saleDate: saleDate
  7326.                     });
  7327.                     return;
  7328.                 }
  7329.                 const diffValue = convertToDecimal(saleTotalValue).minus(convertToDecimal(currentPaymentTotal)).toNumber();
  7330.                 if (Math.abs(diffValue) > PAYMENT_TOLERANCE) {
  7331.                     if (diffValue < 0) {
  7332.                         showErrorAlert('Girilen ödeme tutarı satış tutarını aşıyor. Lütfen ödeme kayıtlarını kontrol edin.');
  7333.                         return;
  7334.                     }
  7335.                     openAutoPaymentModal({
  7336.                         scenario: 'mismatch',
  7337.                         amount: diffValue,
  7338.                         saleTotal: saleTotalValue,
  7339.                         currentPayments: currentPaymentTotal,
  7340.                         saleDate: saleDate
  7341.                     });
  7342.                     return;
  7343.                 }
  7344.                 submitSalesRequest();
  7345.             });
  7346.             function addCommas(number) {
  7347.                 let decimals = 2;
  7348.                 number = (number + '').replace(/[^0-9+\\-Ee.]/g, '');
  7349.                 var n = !isFinite(+number) ? 0 : +number;
  7350.                 var prec = !isFinite(+decimals) ? 0 : Math.abs(decimals);
  7351.                 var sep = ',';
  7352.                 var dec = '.';
  7353.                 var s = '';
  7354.                 var toFixedFix = function(n, prec) {
  7355.                     var k = Math.pow(10, prec);
  7356.                     return '' + (Math.round(n * k) / k).toFixed(prec);
  7357.                 };
  7358.                 s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.');
  7359.                 if (s[0].length > 3) {
  7360.                     s[0] = s[0].replace(/\\B(?=(?:\\d{3})+(?!\\d))/g, sep);
  7361.                 }
  7362.                 if ((s[1] || '').length < prec) {
  7363.                     s[1] = s[1] || '';
  7364.                     s[1] += new Array(prec - s[1].length + 1).join('0');
  7365.                 }
  7366.                 return s.join(dec);
  7367.             }
  7368.             \$(document).on('input change', '#products_sold_totalUnitPurchasePrice, #products_sold_quantity, #products_sold_unAllocatedQuantity, #products_sold_discount, #products_sold_tax', function() {
  7369.                 var purchasePrice = \$('#products_sold_totalUnitPurchasePrice').val() || \"0\";
  7370.                 var purchasePriceClean = parseFloat(purchasePrice.replace(/,/g, \"\")) || 0;
  7371.                 var cost = parseFloat(\$('#hidden-cost-input').val()) || 0;
  7372.                 var quantity = \$('#products_sold_quantity').val() || \"0\";
  7373.                 var quantityClean = parseFloat(quantity.replace(/,/g, \"\")) || 0;
  7374.                 var unAllocatedQuantity = \$('#products_sold_unAllocatedQuantity').val() || \"0\";
  7375.                 var unAllocatedQuantityClean = parseFloat(unAllocatedQuantity.replace(/,/g, \"\")) || 0;
  7376.                 var discountPercentage = \$('#products_sold_discount').val() || \"0\";
  7377.                 var discountPercentageClean = parseFloat(discountPercentage.replace(/,/g, \"\")) || 0;
  7378.                 var taxPercentage = \$('#products_sold_tax').val() || \"0\";
  7379.                 var taxPercentageClean = parseFloat(taxPercentage.replace(/,/g, \"\")) || 0;
  7380.                 var totalQuantity = quantityClean + unAllocatedQuantityClean;
  7381.                 var totalSalePriceBeforeDiscount = purchasePriceClean * totalQuantity;
  7382.                 var discountAmount = (totalSalePriceBeforeDiscount * discountPercentageClean) / 100;
  7383.                 var totalSalePriceAfterDiscount = totalSalePriceBeforeDiscount - discountAmount;
  7384.                 var taxAmount = (totalSalePriceAfterDiscount * taxPercentageClean) / 100;
  7385.                 var totalSalePrice = totalSalePriceAfterDiscount + taxAmount;
  7386.                 \$('#products_sold_totalSalePrice').val(addCommas(totalSalePrice.toFixed(2)));
  7387.                 \$('#products_sold_totalPuchasePrice').val(addCommas(totalSalePrice.toFixed(2)));
  7388.                 cost = roundToDecimal(cost);
  7389.                 var salePriceWithoutTax = totalSalePrice / (1 + taxPercentageClean / 100);
  7390.                 var totalCost = totalQuantity * cost;
  7391.                 var profit = salePriceWithoutTax - totalCost;
  7392.                 var profitSpan;
  7393.                 if (profit > 0) {
  7394.                     profitSpan = \"<span style='color:green'>\" + profit.toFixed(2).toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, \",\") + \" €</span>\";
  7395.                 } else {
  7396.                     profitSpan = \"<span style='color:red'>\" + profit.toFixed(2).toString().replace(/\\B(?=(\\d{3})+(?!\\d))/g, \",\") + \" €</span>\";
  7397.                 }
  7398.                 \$('.profit-info-span').html(profitSpan);
  7399.             });
  7400.             \$('#payment_amount').mask(\"#,##0.00\", {
  7401.                 reverse: true
  7402.             });
  7403.             // Show/Hide Voucher Code field based on Payment Method
  7404.             \$('#payment_paymentMethod').on('change', function() {
  7405.                 var selectedText = \$(this).find(\"option:selected\").text().trim().toLowerCase();
  7406.                 var \$voucherField = \$('#payment_voucherCode');
  7407.                 var \$voucherLabel = \$('label[for=\"payment_voucherCode\"]');
  7408.                 
  7409.                 if (selectedText.includes('hediye') || selectedText.includes('gift') || selectedText.includes('çek')) {
  7410.                     \$voucherField.show();
  7411.                     \$voucherLabel.show();
  7412.                     \$voucherField.attr('required', 'required');
  7413.                 } else {
  7414.                     \$voucherField.hide();
  7415.                     \$voucherLabel.hide();
  7416.                     \$voucherField.val('');
  7417.                     \$voucherField.removeAttr('required');
  7418.                 }
  7419.             });
  7420.             \$('#sales_form_customer').select2({
  7421.                 theme: 'bootstrap4',
  7422.                 dropdownCssClass: 'custom-select-dropdown',
  7423.                 placeholder: 'Müşteri Seçin',
  7424.                 allowClear: true
  7425.             });
  7426.             \$('.js-edit-customer').on('click', function() {
  7427.                 let customerId = \$('#sales_form_customer').val();
  7428.                 if (!customerId) {
  7429.                     showErrorAlert(\"{% trans %} selectCustomerForEdit {% endtrans %}\");
  7430.                 } else {
  7431.                     \$.ajax({
  7432.                         url: '/admin/customer/detail/' + customerId,
  7433.                         type: 'GET',
  7434.                         dataType: 'json',
  7435.                         success: function(response) {
  7436.                             showUpdateModal(customerId, response);
  7437.                         },
  7438.                         error: function(jqXHR, textStatus, errorThrown) {
  7439.                             if (jqXHR.status === 404) {
  7440.                                 showErrorAlert(\"Seçilen müşteri veritabanında bulunamadı.\");
  7441.                             } else {
  7442.                                 showErrorAlert('Müşteri bilgileri yüklenirken bir hata oluştu.');
  7443.                             }
  7444.                             clearCustomerFields();
  7445.                         }
  7446.                     });
  7447.                 }
  7448.             });
  7449.             \$('#sales_form_customer').on('change', function() {
  7450.                 let customerId = \$(this).val();
  7451.                 if (!customerId) {
  7452.                     clearCustomerFields();
  7453.                     return;
  7454.                 }
  7455.                 \$.ajax({
  7456.                     url: '/admin/customer/detail/' + customerId,
  7457.                     type: 'GET',
  7458.                     dataType: 'json',
  7459.                     success: function(response) {
  7460.                         if (!response.phone || !response.email || !response.address) {
  7461.                             showUpdateModal(customerId, response);
  7462.                         } else {
  7463.                             populateCustomerFields(response);
  7464.                         }
  7465.                     },
  7466.                     error: function(jqXHR, textStatus, errorThrown) {
  7467.                         if (jqXHR.status === 404) {
  7468.                             showErrorAlert(\"Seçilen müşteri veritabanında bulunamadı.\");
  7469.                         } else {
  7470.                             showErrorAlert('Müşteri bilgileri yüklenirken bir hata oluştu.');
  7471.                         }
  7472.                         clearCustomerFields();
  7473.                     }
  7474.                 });
  7475.             });
  7476.             function populateCustomerFields(customer) {
  7477.                 \$('#update_customer_fullName').val(customer.fullName);
  7478.                 \$('#update_customer_email').val(customer.email);
  7479.                 \$('#update_customer_phone').val(customer.phone);
  7480.                 \$('#update_customer_address').val(customer.address);
  7481.             }
  7482.             function clearCustomerFields() {
  7483.                 \$('#update_customer_fullName, #update_customer_email, #update_customer_phone, #update_customer_address').val('');
  7484.             }
  7485.             function showUpdateModal(id, customer) {
  7486.                 \$('#update_customer_id').val(id);
  7487.                 \$('#update_customer_email').val(customer.email || '');
  7488.                 \$('#update_customer_phone').val(customer.phone || '');
  7489.                 \$('#update_customer_address').val(customer.address || '');
  7490.                 \$('#update_customer_fullName').val(customer.fullName || '');
  7491.                 \$('#updateCustomerModal').modal('show');
  7492.             }
  7493.             \$('#updateCustomerForm').on('submit', function(e) {
  7494.                 e.preventDefault();
  7495.                 let customerId = \$('#update_customer_id').val();
  7496.                 let formData = {
  7497.                     email: \$('#update_customer_email').val(),
  7498.                     phone: \$('#update_customer_phone').val(),
  7499.                     address: \$('#update_customer_address').val(),
  7500.                     fullName: \$('#update_customer_fullName').val()
  7501.                 };
  7502.                 \$.ajax({
  7503.                     url: '/admin/customer/update/' + customerId,
  7504.                     type: 'POST',
  7505.                     data: formData,
  7506.                     success: function(response) {
  7507.                         \$('#updateCustomerModal').modal('hide');
  7508.                         populateCustomerFields(response);
  7509.                         showSuccessAlert(\"{% trans %} customerUpdateSuccess {% endtrans %}\");
  7510.                     },
  7511.                     error: function(jqXHR, textStatus, errorThrown) {
  7512.                         let errorMessage = 'Güncelleme sırasında bilinmeyen bir hata oluştu.';
  7513.                         try {
  7514.                             const response = JSON.parse(jqXHR.responseText);
  7515.                             if (response && response.message) {
  7516.                                 errorMessage = response.message;
  7517.                             }
  7518.                         } catch (e) {
  7519.                             console.error(\"JSON Parse Error:\", e);
  7520.                             console.error(\"Server Response:\", jqXHR.responseText);
  7521.                         }
  7522.                         showErrorAlert(errorMessage);
  7523.                     }
  7524.                 });
  7525.             });
  7526.             \$('#show-info-btn').on('click', function(e) {
  7527.                 e.preventDefault();
  7528.                 const selectedProductId = \$('#productselect').val();
  7529.                 if (!selectedProductId || selectedProductId <= 0) {
  7530.                     showErrorAlert(\"Detayları görmek için önce bir ürün seçmelisiniz.\");
  7531.                     return;
  7532.                 }
  7533.                 const \$infoContent = \$('#info-details-content');
  7534.                 const \$icon = \$(this).find('i');
  7535.                 \$infoContent.toggle();
  7536.                 if (\$infoContent.is(':visible')) {
  7537.                     \$icon.removeClass('fa-info-circle').addClass('fa-chevron-up');
  7538.                 } else {
  7539.                     \$icon.removeClass('fa-chevron-up').addClass('fa-info-circle');
  7540.                 }
  7541.             });
  7542.             // --- GIFT VOUCHER LOGIC ---
  7543.             // Hediye Kuponu Butonuna Tıklama (Desktop)
  7544.             \$('#btn-gift-voucher').on('click', function() {
  7545.                 openGiftVoucherModal();
  7546.             });
  7547.              // Hediye Kuponu Butonuna Tıklama (Mobile)
  7548.             \$('#btn-gift-voucher-mobile').on('click', function() {
  7549.                 openGiftVoucherModal();
  7550.             });
  7551.             function openGiftVoucherModal() {
  7552.                 const customerId = \$('#sales_form_customer').val();
  7553.                 if (!customerId) {
  7554.                     showErrorAlert('Lütfen önce bir müşteri seçiniz.');
  7555.                     return;
  7556.                 }
  7557.                 // API'den bakiye sorgula
  7558.                 \$.ajax({
  7559.                     url: '/admin/gift-certificates/api/balance/' + customerId,
  7560.                     method: 'GET',
  7561.                     success: function(response) {
  7562.                         if (response.error) {
  7563.                             showErrorAlert(response.error);
  7564.                             return;
  7565.                         }
  7566.                         \$('#voucher-total-balance').text(response.formatted);
  7567.                         \$('#voucher-total-balance').data('balance', response.balance);
  7568.                         \$('#voucher-customer-name').text(response.customerName); // Set customer name
  7569.                         \$('#voucher-use-amount').val(''); // Inputu temizle
  7570.                          // Varsayılan olarak kalanı doldurmayı deneyebiliriz ama kullanıcı girişi daha iyi
  7571.                         const totals = aggregateSoldTotals();
  7572.                          const paymentTotal = convertToDecimal(calculateTotalPaymentAmount());
  7573.                         const remaining = totals.grandTotal.minus(paymentTotal);
  7574.                          if (remaining.greaterThan(0)) {
  7575.                              // Eğer kalan miktar, bakiyeden küçükse kalanı, büyükse bakiyeyi öner
  7576.                              const balance = new Decimal(response.balance);
  7577.                              const suggested = remaining.lessThan(balance) ? remaining : balance;
  7578.                              \$('#voucher-use-amount').val(suggested.toNumber());
  7579.                          }
  7580.                         \$('#gift-voucher-usage-modal').modal('show');
  7581.                     },
  7582.                     error: function() {
  7583.                         showErrorAlert('Müşteri hediye çeki bakiyesi sorgulanırken bir hata oluştu.');
  7584.                     }
  7585.                 });
  7586.             }
  7587.             // Hediye Çeki Kullanımını Onayla
  7588.             \$('#btn-confirm-voucher-usage').on('click', function() {
  7589.                 const amount = parseFloat(\$('#voucher-use-amount').val());
  7590.                 const balance = parseFloat(\$('#voucher-total-balance').data('balance'));
  7591.                 if (isNaN(amount) || amount <= 0) {
  7592.                     showErrorAlert('Lütfen geçerli bir miktar giriniz.');
  7593.                     return;
  7594.                 }
  7595.                 if (amount > balance) {
  7596.                     showErrorAlert('Girdiğiniz miktar, toplam bakiyeden fazla olamaz.');
  7597.                     return;
  7598.                 }
  7599.                 // Ödeme Yöntemini Bul (Hediye Çeki / Gift Voucher)
  7600.                 let voucherMethodId = null;
  7601.                 // 1. Yöntem: Backend'den gelen veriyi kullan (En Sağlam)
  7602.                 // 1. Yöntem: Backend'den gelen veriyi kullan (En Sağlam)
  7603.                 {% if paymentMethods is defined %}
  7604.                     const methods = [
  7605.                         {% for pm in paymentMethods %}
  7606.                             { id: \"{{ pm.id }}\", name: \"{{ pm.name|e('js') }}\" },
  7607.                         {% endfor %}
  7608.                     ];
  7609.                     const voucherMethod = methods.find(m => 
  7610.                         (m.name && m.name.toLowerCase().includes('hediye')) || 
  7611.                         (m.name && m.name.toLowerCase().includes('gift')) || 
  7612.                         (m.name && m.name.toLowerCase().includes('kupon'))
  7613.                     );
  7614.                     if (voucherMethod) {
  7615.                         voucherMethodId = voucherMethod.id;
  7616.                     }
  7617.                 {% endif %}
  7618.                 // 2. Yöntem: Eğer yukarıdaki çalışmazsa DOM'dan bulmayı dene
  7619.                 if (!voucherMethodId) {
  7620.                      const \$methodSelect = \$('select[name=\"paymentMethod[]\"]').first(); // Tablodaki herhangi bir select
  7621.                      \$methodSelect.find('option').each(function() {
  7622.                         const text = \$(this).text().toLowerCase();
  7623.                         if (text.includes('hediye') || text.includes('gift') || text.includes('kupon')) {
  7624.                             voucherMethodId = \$(this).val();
  7625.                             return false; // break
  7626.                         }
  7627.                     });
  7628.                 }
  7629.                 
  7630.                 // 3. Yöntem: Modal Select
  7631.                 if (!voucherMethodId) {
  7632.                      const \$modalSelect = \$('#add-payment-modal select[name=\"paymentMethod\"]');
  7633.                      \$modalSelect.find('option').each(function() {
  7634.                         const text = \$(this).text().toLowerCase();
  7635.                         if (text.includes('hediye') || text.includes('gift') || text.includes('kupon')) {
  7636.                             voucherMethodId = \$(this).val();
  7637.                             return false; // break
  7638.                         }
  7639.                     });
  7640.                 }
  7641.                 if (!voucherMethodId) {
  7642.                      // Eğer modal select'inde yoksa, bir de manuel tanımlı ID varsa onu kontrol et (opsiyonel)
  7643.                      // Veya uyarı ver
  7644.                      // Fallback: İlk metodun id'sini alma riskine girmeyelim, kullanıcıya soralım veya hata verelim.
  7645.                      // Ancak genelde bir \"Hediye Çeki\" metodu olmalı.
  7646.                      // Şimdilik hata verelim.
  7647.                      showErrorAlert('Sistemde \"Hediye Çeki\" ödeme yöntemi bulunamadı. Lütfen yönetim panelinden ekleyiniz.');
  7648.                      return;
  7649.                 }
  7650.                 // Yeni ödeme satırı ekle
  7651.                 const payment = {
  7652.                     uuid: crypto.randomUUID(),
  7653.                     amount: amount,
  7654.                     status: \"0\", // Ödendi
  7655.                     paymentDate: new Date().toISOString().split('T')[0], // Bugün
  7656.                     paymentDueDate: new Date().toISOString().split('T')[0], // Bugün
  7657.                     paymentMethod: voucherMethodId,
  7658.                     description: 'Hediye Çeki Kullanımı',
  7659.                     voucherCode: 'AUTO_DEDUCT_FROM_BALANCE' // Backend bunu işleyip ilgili çeklerden düşebilir
  7660.                 };
  7661.                 payments.push(payment);
  7662.                 fetchPaymentForm();
  7663.                 fetchSoldListRows(); // Trigger AVOIR row update
  7664.                 \$('#gift-voucher-usage-modal').modal('hide');
  7665.                 showSuccessAlert(amount + ' TL hediye çeki ödemesi eklendi.');
  7666.             });
  7667.             // calculateTotalPaymentAmount fonksiyonunu global scope'ta bulamadıysak buraya ekleyelim veya mevcut olanı kullanalım
  7668.             function calculateTotalPaymentAmount() {
  7669.                 let total = new Decimal(0);
  7670.                 payments.forEach(function(p) {
  7671.                    total = total.plus(convertToDecimal(p.amount));
  7672.                 });
  7673.                 return total;
  7674.             }
  7675.             // --- END GIFT VOUCHER LOGIC ---
  7676.         });
  7677.         function createPopup(url, window_name = 'example-popup') {
  7678.             var width = 1100;
  7679.             var height = 700;
  7680.             var screen_width = window.screen.width;
  7681.             var screen_height = window.screen.height;
  7682.             var popup_left = (screen_width - width) / 2;
  7683.             var popup_top = (screen_height - height) / 2;
  7684.             var popup_window = window.open(url, window_name, 'width=' + width + ',height=' + height + ',left=' + popup_left + ',top=' + popup_top);
  7685.         }
  7686.     </script>
  7687. {% endblock %}
  7688. ""admin/sales/index.html.twig""/app/templates/admin/sales/index.html.twig");
  7689.     }
  7690. }