Advertisement
SherinKR

budget_tool.html

Mar 2nd, 2024
718
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 16.87 KB | Source Code | 0 0
  1. <!DOCTYPE html>
  2. <html lang="en" dir="ltr">
  3.   <head>
  4.     <meta charset="utf-8">
  5.     <title>Pradan Budget</title>
  6.     <script type="text/javascript">
  7.       $(".allownumeric").on("keypress keyup blur", function(event) {
  8.         $(this).val($(this).val().replace(/[^\d].+/, ""));
  9.         if ((event.which < 48 || event.which > 57)) {
  10.           event.preventDefault();
  11.         }
  12.       });
  13.  
  14.       $(".budget_notes").on("input", function(event) {
  15.         cur_frm.set_value('has_unsaved_changes', 1);
  16.       });
  17.  
  18.       function calculate_totals(row){
  19.         cur_frm.set_value('has_unsaved_changes', 1);
  20.         var total_row = document.querySelectorAll('.total_row');
  21.         var budget_size = cur_frm.doc.budget_size || 0;
  22.  
  23.         // Year wise budget validation
  24.         var year_inputs = document.querySelectorAll('.year_input');
  25.         var year_maxs = document.querySelectorAll('.year_max');
  26.         var row_count = year_maxs.length || 0;
  27.         var year_col_count = (year_inputs.length)/row_count
  28.         var year_max = parseFloat(year_maxs[row].innerHTML) || 0;
  29.         var year_total_cells = document.querySelectorAll('.year_total');
  30.         var year_balance_cells = document.querySelectorAll('.year_balance');
  31.         var year_total = 0;
  32.         for (var i = row * year_col_count; i < (row + 1) * year_col_count; i++) {
  33.          var year_value = parseFloat(year_inputs[i].innerHTML) || 0;
  34.          year_total += year_value;
  35.        }
  36.        year_total_cells[row].innerText = year_total;
  37.        if(year_max<year_total){
  38.          frappe.throw('Total Year wise budget exceeded than maximum Budget assigned!');
  39.        }
  40.        else {
  41.          year_balance_cells[row].innerText = year_max - year_total;
  42.        }
  43.  
  44.        // validate total year max
  45.        var total_year_max = 0
  46.        for(var i = 0; i < year_maxs.length; i++){
  47.          var year_max_val = parseFloat(year_maxs[i].innerHTML) || 0;
  48.          total_year_max += year_max_val
  49.        }
  50.        total_row[0].innerHTML = total_year_max;
  51.        if(budget_size<total_year_max){
  52.          frappe.throw('Total year maximum budget exceeded than Budget Size!');
  53.        }
  54.  
  55.        // FY wise Budget validation
  56.        var fy_inputs = document.querySelectorAll('.fy_input');
  57.        var fy_maxs = document.querySelectorAll('.fy_max')
  58.        fy_maxs[row].innerHTML = year_max;
  59.        var fy_col_count = (fy_inputs.length)/row_count
  60.        var fy_max = parseFloat(fy_maxs[row].innerHTML) || 0;
  61.        var fy_total_cells = document.querySelectorAll('.fy_total');
  62.        var fy_balance_cells = document.querySelectorAll('.fy_balance');
  63.        var fy_total = 0;
  64.        for (var i = row * fy_col_count; i < (row + 1) * fy_col_count; i++) {
  65.          var fy_value = parseFloat(fy_inputs[i].innerHTML) || 0;
  66.          fy_total += fy_value;
  67.        }
  68.        fy_total_cells[row].innerText = fy_total;
  69.        if(fy_max<fy_total){
  70.          frappe.throw('Total FY wise budget exceeded than maximum Budget assigned!');
  71.        }
  72.        else {
  73.          fy_balance_cells[row].innerText = fy_max - fy_total;
  74.        }
  75.  
  76.        // validate total year max
  77.        var total_fy_max = 0
  78.        for(var i = 0; i < fy_maxs.length; i++){
  79.          var fy_max_val = parseFloat(fy_maxs[i].innerHTML) || 0;
  80.          total_fy_max += fy_max_val
  81.        }
  82.        total_row[year_col_count+3].innerHTML = total_fy_max;
  83.        if(budget_size<total_fy_max){
  84.          frappe.throw('Total FY maximum budget exceeded than Budget Size!');
  85.        }
  86.  
  87.        // Set total row
  88.        year_totals = []
  89.        for (var i=0; i<(year_inputs.length/year_col_count); i++) {
  90.          for (var j=0; j<year_col_count; j++) {
  91.            var amount = parseFloat(year_inputs[(i*year_col_count)+j].innerHTML) || 0;
  92.            if(i){
  93.              year_totals[j] += amount;
  94.              total_row[j+1].innerHTML = year_totals[j];
  95.            }
  96.            else {
  97.              year_totals[j] = amount
  98.            }
  99.          }
  100.        }
  101.  
  102.        var year_total_amount = 0;
  103.        year_total_cells.forEach(row => {
  104.           year_total_amount += parseFloat(row.innerHTML);
  105.         });
  106.         var year_balance_amount = 0;
  107.         year_balance_cells.forEach(row => {
  108.           year_balance_amount += parseFloat(row.innerHTML);
  109.         });
  110.         total_row[year_col_count+1].innerHTML = year_total_amount;
  111.         total_row[year_col_count+2].innerHTML = year_balance_amount;
  112.  
  113.         fy_totals = []
  114.         for (var i=0; i<(fy_inputs.length/fy_col_count); i++) {
  115.          for (var j=0; j<fy_col_count; j++) {
  116.            var amount = parseFloat(fy_inputs[(i*fy_col_count)+j].innerHTML) || 0;
  117.            if(i){
  118.              fy_totals[j] += amount;
  119.              total_row[year_col_count+4+j].innerHTML = fy_totals[j];
  120.            }
  121.            else {
  122.              fy_totals[j] = amount
  123.            }
  124.          }
  125.        }
  126.  
  127.        var fy_total_amount = 0;
  128.        fy_total_cells.forEach(row => {
  129.           fy_total_amount += parseFloat(row.innerHTML);
  130.         });
  131.         var fy_balance_amount = 0;
  132.         fy_balance_cells.forEach(row => {
  133.           fy_balance_amount += parseFloat(row.innerHTML);
  134.         });
  135.         total_row[year_col_count+fy_col_count+4].innerHTML = fy_total_amount;
  136.         total_row[year_col_count+fy_col_count+5].innerHTML = fy_balance_amount;
  137.       }
  138.  
  139.       function allocate_budget(sub_budget_item){
  140.         var project = cur_frm.doc.project;
  141.         frappe.call({
  142.           method:'pradan.pradan.doctype.budget_tool.budget_tool.get_allocation_data',
  143.           args: {
  144.             'project': project,
  145.             'sub_budget_item': sub_budget_item
  146.           },
  147.           freeze: true,
  148.           freeze_message: __("Fetching teams.."),
  149.           callback: (r) => {
  150.             if(r.message){
  151.               var data = r.message;
  152.               if(data.fiscal_years.length){
  153.                 allocate_budget_popup(project, sub_budget_item, data.fiscal_years, data.available_amount, data.labels);
  154.               }
  155.             }
  156.           }
  157.         });
  158.       }
  159.  
  160.       function clear_cell_value(cell) {
  161.         if (cell.innerHTML === '0') {
  162.           cell.innerHTML = '';
  163.         }
  164.       }
  165.  
  166.       function allocate_budget_popup(project, sub_budget_item, fiscal_years, available_amount, labels){
  167.         let d = new frappe.ui.Dialog({
  168.           title: 'Team Allocation',
  169.           size: "large",
  170.           fields: [
  171.           {
  172.             label: "Fiscal Year",
  173.             fieldname: "fiscal_year",
  174.             fieldtype: "Select",
  175.             options: fiscal_years,
  176.             reqd: 1,
  177.             onchange: function(e) {
  178.               var primary_action_label = 'Allocate';
  179.               var selected_fiscal_year = this.value;
  180.               var idx = fiscal_years.indexOf(selected_fiscal_year);
  181.               primary_action_label = labels[idx];
  182.               d.set_value('allocated_amount', available_amount[idx]);
  183.               d.set_primary_action(primary_action_label, (values) => {
  184.                 allocate_budget_to_teams(project, sub_budget_item, values.fiscal_year, values);
  185.                 d.hide();
  186.               });
  187.               frappe.db.get_value("Budget Item", sub_budget_item, 'parent_budget_item').then((result) => {
  188.                 d.set_value('budget_item', result.message.parent_budget_item)
  189.                 d.set_value('sub_budget_item', sub_budget_item)
  190.               });
  191.             }
  192.           },
  193.           {
  194.             label: "Budget Item",
  195.             fieldname: "budget_item",
  196.             fieldtype: "Link",
  197.             options: 'Budget Item',
  198.             read_only: 1,
  199.             depends_on: "eval: doc.fiscal_year"
  200.           },
  201.           {
  202.             label: "Sub Budget Item",
  203.             fieldname: "sub_budget_item",
  204.             fieldtype: "Link",
  205.             options: 'Budget Item',
  206.             read_only: 1,
  207.             depends_on: "eval: doc.fiscal_year"
  208.           },
  209.           {
  210.             label: "Available Amount",
  211.             fieldname: "allocated_amount",
  212.             fieldtype: "Currency",
  213.             read_only: 1,
  214.             default: 0,
  215.             depends_on: "eval: doc.fiscal_year",
  216.             onchange: function(e) {
  217.               var allocated_amount = this.value;
  218.               var fiscal_year = d.get_value('fiscal_year');
  219.               frappe.call({
  220.                 method: 'pradan.pradan.doctype.pradan_budget.pradan_budget.get_team_wise_budget',
  221.                 args: {
  222.                   project: project,
  223.                   available_amount: allocated_amount,
  224.                   sub_budget_item: sub_budget_item,
  225.                   fiscal_year: fiscal_year
  226.                 },
  227.                 freeze: true,
  228.                 freeze_message: __("Fetching team details.."),
  229.                 callback: (r) => {
  230.                   if(r.message){
  231.                     let data = r.message.team_wise_budget;
  232.                     d.fields_dict.team_wise_budget.df.read_only = r.message.is_salary_head
  233.                     d.fields_dict.team_wise_budget.df.fields[2].read_only = r.message.is_salary_head
  234.                     d.fields_dict.team_wise_budget.df.data = data
  235.                     let available_amount = parseFloat(d.get_value('allocated_amount')) || 0;
  236.                     let allocated_amount = 0;
  237.                     data.forEach(row => {
  238.                       allocated_amount += row.allocated_amount;
  239.                     });
  240.                     let balance_amount = available_amount - allocated_amount;
  241.                     d.set_value('balance_amount', balance_amount);
  242.                     d.fields_dict.team_wise_budget.grid.refresh();
  243.                   }
  244.                   else {
  245.                     frappe.throw('No team has allocated to this Project')
  246.                   }
  247.                 }
  248.               });
  249.             }
  250.           },
  251.           {
  252.             label: "Team wise Budget",
  253.             fieldname: "team_wise_budget",
  254.             fieldtype: "Table",
  255.             reqd: 1,
  256.             cannot_add_rows: true,
  257.             cannot_delete_rows: true,
  258.             cannot_delete_all_rows: true,
  259.             in_place_edit: true,
  260.             depends_on: "eval: doc.fiscal_year",
  261.             fields: [
  262.               {
  263.                 fieldtype: 'Link',
  264.                 label: 'Project',
  265.                 fieldname: 'project',
  266.                 options: 'Project',
  267.                 in_list_view: 1,
  268.                 reqd: 1,
  269.                 read_only: 1
  270.               },
  271.               {
  272.                 fieldtype: 'Link',
  273.                 label: 'Teams',
  274.                 fieldname: 'teams',
  275.                 options: 'Branch',
  276.                 in_list_view: 1,
  277.                 reqd: 1,
  278.                 read_only: 1
  279.               },
  280.               {
  281.                 fieldtype: 'Currency',
  282.                 label: 'Allocated Amount',
  283.                 fieldname: 'allocated_amount',
  284.                 in_list_view: 1,
  285.                 reqd: 1,
  286.                 default: 0,
  287.                 onchange: function(e) {
  288.                   var available_amount = parseFloat(d.get_value('allocated_amount')) || 0;
  289.                   var table_data = d.get_value('team_wise_budget');
  290.                   var allocated_amount = 0;
  291.                   table_data.forEach(row => {
  292.                     allocated_amount += row.allocated_amount;
  293.                   });
  294.                   var balance_amount = available_amount - allocated_amount;
  295.                   d.set_value('balance_amount', balance_amount);
  296.                   // if(available_amount<allocated_amount){
  297.                  //   frappe.throw('Total allocation should not exceed than the available amount!');
  298.                  // }
  299.                }
  300.              },
  301.              {
  302.                fieldtype: 'Data',
  303.                label: 'Remarks',
  304.                fieldname: 'remarks',
  305.                in_list_view: 1
  306.              },
  307.            ]
  308.          },
  309.          {
  310.            label: "Balance Amount",
  311.            fieldname: "balance_amount",
  312.            fieldtype: "Currency",
  313.            default: 0,
  314.            read_only: 1
  315.          }
  316.          ]
  317.        });
  318.        d.show();
  319.      }
  320.  
  321.      function allocate_budget_to_teams(project, sub_budget_item, fiscal_year, values){
  322.        frappe.call({
  323.          method: 'pradan.pradan.doctype.pradan_budget.pradan_budget.allocate_budget_to_teams',
  324.          args: {
  325.            project: project,
  326.            sub_budget_item: sub_budget_item,
  327.            fiscal_year: fiscal_year,
  328.            values: values
  329.          },
  330.          freeze: true,
  331.          freeze_message: 'Allocating to teams..',
  332.          callback: (r) => {
  333.             cur_frm.trigger('project');
  334.           }
  335.         });
  336.       }
  337.     </script>
  338.   </head>
  339.   <body>
  340.     <div class="tableFixHead">
  341.       <table id="data-table" class="div1">
  342.       <thead>
  343.         <tr>
  344.           <th class="text-center">
  345.             No
  346.           </th>
  347.           {% for column in columns %}
  348.             <th>{{column}}</th>
  349.           {% endfor %}
  350.           <th class="text-center">
  351.             Allocate/<br>Reallocate
  352.           </th>
  353.         </tr>
  354.       </thead>
  355.       <tbody>
  356.         {% set table_row = {'id': 0} %}
  357.         {% for row in data %}
  358.         <tr>
  359.           <td class="text-center">{{loop.index}}</td>
  360.           {% set is_sub_total_row = {'id': 0} %}
  361.           {% for col in row %}
  362.             {% if col.class_name == 'sub_total' %}
  363.               {% if loop.index == 1 %}
  364.                 {% if is_sub_total_row.update({'id': 1}) %} {% endif %}
  365.               {% endif %}
  366.             {% endif %}
  367.             {% if col.primary %}
  368.               {% if col.ref_link %}
  369.                 <td><a href="{{col.ref_link}}" target="_blank">{{col.value}}</a></td>
  370.               {% else %}
  371.                 <td>{{col.value}}</td>
  372.               {% endif %}
  373.             {% else %}
  374.               {% if col.read_only %}
  375.                 {% if col.class_name %}
  376.                   {% if col.style %}
  377.                     <td class="{{ col.class_name }}" style="{{ col.style }}">{{col.value}}</td>
  378.                   {% else %}
  379.                     <td class="{{ col.class_name }}">{{col.value}}</td>
  380.                   {% endif %}
  381.                 {% else %}
  382.                   <td>{{col.value}}</td>
  383.                 {% endif %}
  384.               {% else %}
  385.                 {% if col.type == 'text' %}
  386.                   {% if col.class_name %}
  387.                     <td class="{{ col.class_name }}" contenteditable="true">{{col.value}}</td>
  388.                   {% else %}
  389.                     <td contenteditable="true">{{col.value}}</td>
  390.                   {% endif %}
  391.                 {% endif %}
  392.                 {% if col.type == 'number' %}
  393.                   {% if col.class_name %}
  394.                     <td class="allownumeric {{ col.class_name }}" contenteditable="true" oninput="calculate_totals({{table_row.id}})" onclick=clear_cell_value(this) onfocus=clear_cell_value(this) style="background-color: {{col.bg_color}}">{{col.value}}</td>
  395.                   {% else %}
  396.                     <td class="allownumeric" contenteditable="true" oninput="calculate_totals({{table_row.id}})" onclick=clear_cell_value(this) onfocus=clear_cell_value(this) style="background-color: {{col.bg_color}}">{{col.value}}</td>
  397.                   {% endif %}
  398.                 {% endif %}
  399.               {% endif %}
  400.             {% endif %}
  401.             {% if col.type == 'button' %}
  402.               <td class="text-center" style="padding-top:5px; padding-bottom:5px;">
  403.                 {% if col.allocated %}
  404.                   <button class="btn btn-primary btn-xs" type="button" title="{{col.message}}" disabled>Allocate</button>
  405.                 {% else %}
  406.                   <button class="btn btn-primary btn-xs" type="button" onclick="allocate_budget('{{ row[2].value }}')">Allocate</button>
  407.                 {% endif  %}
  408.               </td>
  409.             {% endif %}
  410.           {% endfor %}
  411.         </tr>
  412.         {% if is_sub_total_row.id == 0 %}
  413.           {% if table_row.update({'id': table_row.id + 1}) %} {% endif %}
  414.         {% endif %}
  415.         {% endfor %}
  416.         {% if total_row %}
  417.           <tr>
  418.             {% for row in total_row %}
  419.               {% if loop.index <= 5 %}
  420.                {% if loop.index ==1 %}
  421.                  <th style="border-right:0 !important;"> {{ row.value }} </th>
  422.                 {% elif loop.index ==5 %}
  423.                   <th style="border-left:0 !important;"> {{ row.value }} </th>
  424.                 {% else %}
  425.                   <th style="border-left:0 !important; border-right:0 !important;"> {{ row.value }} </th>
  426.                 {% endif %}
  427.               {% else %}
  428.                 <th class="text-right total_row"> {{ row.value }} </th>
  429.               {% endif %}
  430.             {% endfor %}
  431.             <th style="border-right:0 !important;"></th>
  432.             <th style="border-left:0 !important;"></th>
  433.           </tr>
  434.         {% endif %}
  435.       </tbody>
  436.     </table>
  437.     <br><br>
  438.     </div>
  439.   </body>
  440. </html>
  441.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement