Plugin Directory

Changeset 3444321


Ignore:
Timestamp:
01/21/2026 05:33:05 PM (2 months ago)
Author:
catapulto
Message:

Release #221 2026-01-21

Location:
catapultodelivery/trunk
Files:
3 added
32 edited

Legend:

Unmodified
Added
Removed
  • catapultodelivery/trunk/assets/css/admin.css

    r3417476 r3444321  
     1.ctpt_tab_hidden {
     2    display: none;
     3}
    14.ctpt_tbl {
    25    width: 100%;
     
    205208    max-width: 240px !important;
    206209}
     210
     211/* Warehouses */
     212.ctpt_wh_actions p {
     213    display: flex;
     214    height: 34px;
     215    align-items: center;
     216    float: left;
     217    margin: 0 20px 0 0;
     218    margin-top: 0 !important;
     219}
     220.ctpt_wh_actions select {
     221    float:left;
     222}
     223.ctpt_wh_actions button {
     224    float: left;
     225    margin-left: 30px;
     226    height: 34px;
     227}
     228
     229.ctpt_warehouse {
     230    border: 1px solid #000;
     231}
     232.ctpt_warehouse_after td {
     233    padding: 8px;
     234}
     235
     236.ctpt_sender {
     237    padding-right: 20px;
     238    vertical-align: top !important;
     239}
     240.ctpt_operators {
     241    padding-left: 20px;
     242    vertical-align: top !important;
     243}
     244.ctpt_sender label,
     245.ctpt_operators label {
     246    width: 150px;
     247    min-width: 150px;
     248    max-width: 150px;
     249}
     250.ctpt_sender fieldset {
     251    width: 100%;
     252    display: flex;
     253    gap: 20px;
     254    align-items: center;
     255}
     256.ctpt_sender input[type=text] {
     257    width: 100% !important;
     258}
     259.ctpt_sender fieldset fieldset {
     260
     261}
     262
     263.ctpt_operators fieldset {
     264    width: 100%;
     265    display: flex;
     266    gap: 20px;
     267    align-items: center;
     268}
     269.ctpt_bl_d4 {
     270    flex-basis: 25%;
     271}
     272.ctpt_operators input[type=text],
     273.ctpt_operators select {
     274    width: 100% !important;
     275}
     276
     277.ctpt_wh_delete_wr {
     278    width: 100%;
     279    display: flex;
     280    justify-content: end;
     281}
     282
     283#ctpt_wh_delete {
     284    background: #D30000;
     285}
     286#ctpt_wh_delete:hover:not(:disabled) {
     287    background: var(--wc-red);
     288}
     289
     290.ctpt_wh_select_dlv_code.hid input {
     291    display: none;
     292}
     293
     294.ctpt_warehouse.new_wh {
     295    display: none;
     296}
     297
     298.ctpt_err {
     299    border-color: #D30000 !important;
     300}
     301
     302
     303/* /Warehouses */
     304
     305
  • catapultodelivery/trunk/assets/css/send_panel.css

    r3417476 r3444321  
    1717
    1818.ctpt_order_panel input[type=text] {
    19     width: 100%;
     19    width: 98%;
    2020    margin-bottom: 8px;
    2121}
     
    3838.ctpt_datablock {
    3939    width: 100%;
     40    overflow: hidden;
    4041}
    4142
     
    4647.ctpt_warnempty {
    4748    margin-top: 10px !important;
    48     font-weight: bold;
    4949    display: none;
    5050}
     51
     52/* Cargoes */
     53
     54.ctpt_cargowin_close {
     55    position: absolute;
     56    right: 8px;
     57    top: 55px;
     58    width: 30px;
     59    height: 30px;
     60    cursor: pointer;
     61}
     62.ctpt_cargowin_close:before,
     63.ctpt_cargowin_close:after {
     64    display: block;
     65    content: '';
     66    position: absolute;
     67    left:50%;
     68    top: 50%;
     69    transform:translate(-50%,-50%) rotate(-45deg);
     70    width: 33px;
     71    height: 2px;
     72    background:#000;
     73    margin-left: -1px;
     74    transition: 0.5s;
     75}
     76.ctpt_cargowin_close:after {
     77    transform:translate(-50%,-50%) rotate(45deg);
     78}
     79.ctpt_cargowin_close:hover:before,
     80.ctpt_cargowin_close:hover:after {
     81    background-color: #0d6efd;
     82}
     83
     84.rate_update_errors,
     85.rate_update_success {
     86    display: none;
     87    margin-top: 20px;
     88}
     89body {
     90    max-height: 100%;
     91}
     92
     93.body {
     94    min-height: 100vh;
     95    height: auto !important;
     96    padding-bottom: 50px;
     97}
     98.ctpt_cargo_table {
     99    width: 800px;
     100    margin: 0 auto;
     101    padding: 20px;
     102    background: #fff;
     103    border-radius: 20px;
     104    position: relative;
     105
     106    -webkit-box-shadow: 4px 4px 50px 0px rgba(34, 60, 80, 0.25);
     107    -moz-box-shadow: 4px 4px 50px 0px rgba(34, 60, 80, 0.25);
     108    box-shadow: 4px 4px 50px 0px rgba(34, 60, 80, 0.25);
     109
     110}
     111
     112.cargoes {
     113    width: 100%;
     114}
     115.cargo {
     116    padding: 10px;
     117    border: 1px solid #ccc;
     118    margin-bottom: 20px;
     119    position: relative;
     120}
     121.cargo .close {
     122    position: absolute;
     123    right: 8px;
     124    top: 8px;
     125    width: 20px;
     126    height: 20px;
     127    cursor: pointer;
     128}
     129.cargo .close:before,
     130.cargo .close:after {
     131    display: block;
     132    content: '';
     133    position: absolute;
     134    left:50%;
     135    top: 50%;
     136    transform:translate(-50%,-50%) rotate(-45deg);
     137    width: 22px;
     138    height: 1px;
     139    background:#000;
     140    margin-left: -1px;
     141    transition: 0.5s;
     142}
     143.cargo .close:after {
     144    transform:translate(-50%,-50%) rotate(45deg);
     145}
     146.cargo .close:hover:before,
     147.cargo .close:hover:after {
     148    background-color: #0d6efd;
     149}
     150
     151.ctpt_cargo_table table {
     152    width: 100%;
     153}
     154
     155.ctpt_cargo_table h1 {
     156    margin-bottom: 30px;
     157    text-align:center;
     158}
     159
     160.ctpt_cargo_table .hdr {
     161    width: 100%;
     162    display: table;
     163    margin-bottom: 20px;
     164}
     165.ctpt_cargo_table .crg_name {
     166    text-align: center;
     167    width: 100%;
     168    font-weight: 700;
     169}
     170
     171.ctpt_cargo_table .left {
     172    float: left;
     173    width: 50%;
     174}
     175
     176.ctpt_cargo_table input[type=text] {
     177    height: 26px;
     178}
     179
     180.ctpt_cargo_table .cargo_l,
     181.ctpt_cargo_table .cargo_w,
     182.ctpt_cargo_table .cargo_h,
     183.ctpt_cargo_table .gds_l,
     184.ctpt_cargo_table .gds_w,
     185.ctpt_cargo_table .gds_h {
     186    float: left;
     187    width: 65px;
     188}
     189
     190.ctpt_cargo_table .cargo_wei {
     191    width: 149px;
     192}
     193
     194.ctpt_cargo_table .gds_wei {
     195    width: 80px;
     196    margin: 0 auto;
     197    display: block;
     198}
     199
     200.ctpt_cargo_table .gds_art {
     201    width: 140px;
     202    margin: 0 auto;
     203    display: block;
     204}
     205
     206.ctpt_cargo_table .gabs_wr {
     207    display: table;
     208    margin: 0 auto;
     209}
     210.ctpt_cargo_table .gabs_wr span {
     211    display: inline-block;
     212    float: left;
     213    line-height: 26px;
     214    padding: 0 5px;
     215    font-weight: 500;
     216}
     217
     218.ctpt_cargo_table .cargo_gabs,
     219.ctpt_cargo_table .cargo_wei {
     220    display: table;
     221    width: 100%;
     222    margin-bottom: 15px;
     223}
     224.ctpt_cargo_table .cargo_gabs p,
     225.ctpt_cargo_table .cargo_wei p {
     226    margin: 0;
     227    line-height: 26px;
     228    display: block;
     229    width: 130px;
     230    float: left;
     231}
     232
     233.ctpt_cargo_table .cargo_gabs .gabs_wr,
     234.ctpt_cargo_table .cargo_wei .field_wr {
     235    float: left;
     236}
     237
     238.ctpt_cargo_table .hdr button {
     239    display: block;
     240    margin-bottom: 10px;
     241}
     242
     243.ctpt_cargo_table .gds_name {
     244    text-align: center;
     245    padding-bottom: 5px;
     246}
     247
     248.ctpt_cargo_table th {
     249    text-align: center;
     250    padding: 0 5px;
     251}
     252.ctpt_cargo_table td {
     253    padding: 0 5px;
     254}
     255
     256.ctpt_cargo_table .line {
     257    height: 11px;
     258    position: relative;
     259}
     260.ctpt_cargo_table .line:before {
     261    display: block;
     262    content: "";
     263    position: absolute;
     264    left: 0;
     265    top: 50%;
     266    width: 100%;
     267    height: 1px;
     268    transform: translateY(-50%);
     269    background: #000;
     270}
     271
     272.ctpt_cargo_table .gds_cnt {
     273    display: flex;
     274    padding: 0 10px;
     275    justify-content: center;
     276}
     277.ctpt_cargo_table .gds_cnt p {
     278    margin-bottom: 0;
     279    margin-top: 0;
     280    float: left;
     281    margin-right: 10px;
     282    line-height: 26px;
     283}
     284
     285.ctpt_cargo_table .move_ico {
     286    margin-top: 3px;
     287    width: 20px;
     288    height: 20px;
     289    float: left;
     290    position: relative;
     291    cursor: pointer;
     292}
     293.ctpt_cargo_table .move_ico:before,
     294.ctpt_cargo_table .move_ico:after {
     295    display: block;
     296    content: "";
     297    position: absolute;
     298    left: 0;
     299    top: 0;
     300    width: 100%;
     301    height: 100%;
     302    background: url(../images/move.svg) no-repeat;
     303    background-size: contain;
     304    transition: 0.5s;
     305}
     306.ctpt_cargo_table .move_ico:after {
     307    opacity: 0;
     308    background-image: url(../images/move_blue.svg);
     309}
     310.ctpt_cargo_table .move_ico:hover:before {
     311    opacity: 0;
     312}
     313.ctpt_cargo_table .move_ico:hover:after {
     314    opacity: 1;
     315}
     316
     317.ctpt_cargo_table .gds_price p {
     318    line-height: 26px;
     319    text-align: center;
     320    margin: 0;
     321}
     322
     323.ctpt_cargo_table .btm_buttons {
     324    display: table;
     325    width: 100%;
     326    padding-top: 30px;
     327}
     328.ctpt_cargo_table .btm_buttons .btn {
     329    float: left;
     330    margin-right: 10px;
     331}
     332.ctpt_cargo_table .btm_buttons .btn-primary {
     333    float: right;
     334}
     335
     336/* Popup window */
     337.ctpt_move_win {
     338    border: 1px solid #999;
     339    position: absolute;
     340    left: -100000px;
     341    top:0;
     342    opacity: 0;
     343    transition: left 0s linear 0.5s, top 0s linear 0.5s, opacity 0.5s linear 0s;
     344    z-index: 50;
     345    width: 150px;
     346    background: #fff;
     347    border-radius: 4px;
     348    -webkit-box-shadow: 10px 10px 19px 0px rgba(34, 60, 80, 0.4);
     349    -moz-box-shadow: 10px 10px 19px 0px rgba(34, 60, 80, 0.4);
     350    box-shadow: 10px 10px 19px 0px rgba(34, 60, 80, 0.4);
     351    padding: 20px 5px 5px 5px;
     352}
     353.ctpt_move_win.sh {
     354    opacity: 1;
     355    transition: left 0s linear 0s, top 0s linear 0s, opacity 0.5s linear 0s;
     356}
     357
     358.ctpt_move_win .close {
     359    position: absolute;
     360    right: 8px;
     361    top: 8px;
     362    width: 20px;
     363    height: 20px;
     364    cursor: pointer;
     365}
     366.ctpt_move_win .close:before,
     367.ctpt_move_win .close:after {
     368    display: block;
     369    content: '';
     370    position: absolute;
     371    left:50%;
     372    top: 50%;
     373    transform:translate(-50%,-50%) rotate(-45deg);
     374    width: 22px;
     375    height: 1px;
     376    background:#000;
     377    margin-left: -1px;
     378    transition: 0.5s;
     379}
     380.ctpt_move_win .close:after {
     381    transform:translate(-50%,-50%) rotate(45deg);
     382}
     383.ctpt_move_win .close:hover:before,
     384.ctpt_move_win .close:hover:after {
     385    background-color: #0d6efd;
     386}
     387
     388.ctpt_move_win > p {
     389    text-align: center;
     390    padding-right: 10px;
     391}
     392.ctpt_move_win p {
     393    font-size: 12px;
     394    margin-bottom: 15px;
     395}
     396.ctpt_move_win select {
     397    width: 100%;
     398    margin-bottom: 15px;
     399}
     400.ctpt_move_win .place {
     401    width: 100%;
     402    display: flex;
     403    margin-bottom: 15px;
     404    justify-content: center;
     405}
     406.ctpt_move_win .place p {
     407    padding-right: 5px;
     408    margin-bottom: 0;
     409    margin-top: 0;
     410    line-height: 26px;
     411}
     412.ctpt_move_win input {
     413    width: 50px;
     414    height: 26px;
     415}
     416.ctpt_move_win input.err {
     417    background-color: #ffb3b3;
     418}
     419.ctpt_move_win .btn {
     420    width: 100%;
     421}
     422
     423.ctpt_crg_itm_warn p {
     424    text-align: center;
     425    width: 100%;
     426    color: #f00;
     427    margin: 0;
     428    font-size:12px;
     429    padding-top: 5px;
     430}
     431
     432#ctpt_cargoes {
     433    margin-bottom: 15px;
     434}
     435
     436.cargo_gabs_block {
     437    cursor: pointer;
     438    color: #2271b1;
     439    position:relative;
     440    display: inline-block;
     441}
     442.cargo_gabs_block:before,
     443.cargo_gabs_block:after {
     444    display: block;
     445    font-family: dashicons;
     446    font-feature-settings: normal;
     447    content: "\f343";
     448    width: 20px;
     449    height: 20px;
     450    position: absolute;
     451    right: -30px;
     452    top: 50%;
     453    transform: translateY(-50%);
     454    transition: 0.5s;
     455}
     456.cargo_gabs_block:after {
     457    content: "\f347";
     458    opacity: 0;
     459}
     460.cargo_gabs_block.sh:before {
     461    opacity: 0;
     462}
     463.cargo_gabs_block.sh:after {
     464    opacity: 1;
     465}
     466
     467.cargo_gabs_block_content .cnm {
     468    padding-top: 5px;
     469    font-family: bold;
     470    font-size: 16px;
     471}
     472
     473.cargo_gabs_block_content {
     474    display: none;
     475}
     476
     477.ctpt_hidden {
     478    display: none !important;
     479}
     480
     481.ctpt_hint_block {
     482    display: inline-block;
     483    width:100%;
     484    position:relative;
     485}
     486.ctpt_hint_block p {
     487    float:left;
     488}
     489
     490.ctpt_hintlbl {
     491    margin: 0 5px 0 0;
     492    color: #666;
     493    display: inline-block;
     494    font-style: normal;
     495    height: 16px;
     496    line-height: 16px;
     497    position: relative;
     498    vertical-align: middle;
     499    width: 16px;
     500    font-size: 1.2em;
     501    cursor: help;
     502    float: left;
     503    position: relative;
     504    top: 4px;
     505}
     506.ctpt_hintlbl:before {
     507    font-family: Dashicons;
     508    speak: never;
     509    font-weight: 400;
     510    font-variant: normal;
     511    text-transform: none;
     512    line-height: 1;
     513    -webkit-font-smoothing: antialiased;
     514    margin: 0;
     515    text-indent: 0;
     516    position: absolute;
     517    top: 0;
     518    left: 0;
     519    width: 100%;
     520    height: 100%;
     521    text-align: center;
     522    content: "\f223";
     523    cursor: help;
     524}
     525
     526.ctpt_hint_content {
     527    width: 100%;
     528    z-index: 8675309;
     529    position: absolute;
     530    top: 12px;
     531    pointer-events: none;
     532    left: -10000px;
     533    padding-top: 5px;
     534    opacity: 0;
     535    transition: left 0s linear 0.3s, opacity 0.3s linear 0s;
     536}
     537.ctpt_hint_content.sh {
     538    opacity:1;
     539    left: 0;
     540    transition: left 0s linear 0s, opacity 0.3s linear 0s;
     541}
     542.ctpt_hint_content p {
     543    display: block;
     544    width: 100%;
     545    box-sizing: border-box;
     546    color: #fff;
     547    font-size: .8em;
     548    background: #333;
     549    text-align: center;
     550    border-radius: 3px;
     551    padding: .618em 1em;
     552    box-shadow: 0 1px 3px rgba(0,0,0,.2);
     553}
     554
  • catapultodelivery/trunk/assets/js/admin.js

    r3417476 r3444321  
    11(function($) {
    22    $(document).ready(function () {
     3        const errClass = 'ctpt_err';
    34
    45        $(document).on('click', '.ctpt-tab', function(e){
     
    89            self.addClass('nav-tab-active');
    910
    10             $('.ctpt-tab-content-' + tabsContentLevel).hide();
    11             $('#' + self.data('tab-content-id')).show();
     11            $('.ctpt-tab-content-' + tabsContentLevel).addClass('ctpt_tab_hidden')
     12            $('#' + self.data('tab-content-id')).removeClass('ctpt_tab_hidden')
    1213        });
    1314
     
    4041        });
    4142
    42         $('.ctpt_op_element').each( function(){
    43             let t=$(this);
    44             if (t.find('select option:selected').attr('value') == 'door') t.find('input').val('').css('display','none');
    45         });
    46 
    47         $('.ctpt_op_element select').change( function(){
    48             let t=$(this);
    49             if (t.find('option:selected').attr('value') == 'door') {
    50                 t.next().val('').css('display','none');
    51             } else {
    52                 t.next().css('display','');
    53             }
    54         } );
    55 
    56         $('#ctpt_op_setalldoors').click(function(e){
    57             e.preventDefault();
    58 
    59             $('.ctpt_op_element select option').removeAttr('selected');
    60             $('.ctpt_op_element').each( function() {
    61                 let t=$(this);
    62                 t.find('select option[value=door]').prop('selected', true);
    63                 t.find('input').val('').css('display','none');
    64             } );
    65             $('button[name=save]').removeAttr('disabled');
    66 
    67             return false;
    68         });
    69         $('#ctpt_op_setallwh').click(function(e){
    70             e.preventDefault();
    71 
    72             $('.ctpt_op_element select option').removeAttr('selected');
    73             $('.ctpt_op_element').each( function() {
    74                 let t=$(this);
    75                 t.find('select option[value=warehouse]').prop('selected', true);
    76                 t.find('input').css('display','');
    77             } );
    78             $('button[name=save]').removeAttr('disabled');
    79 
    80             return false;
    81         });
    82 
    8343        function numberValidator(input, validator = /^([0-9]){0,6}$/) {
    8444            let vl = input.value;
     
    12484        }
    12585
     86        if (document.querySelector('#woocommerce_catapultodelivery_isFitting') !== null) {
     87            const isFitting = document.querySelector('#woocommerce_catapultodelivery_isFitting'),
     88                fittingDefaultEnabled = document.querySelector('#woocommerce_catapultodelivery_fittingDefaultEnabled'),
     89                onFittingOff = () => {
     90                    fittingDefaultEnabled.checked = false;
     91                    fittingDefaultEnabled.setAttribute('disabled', 'disabled');
     92                };
     93            isFitting.onchange = function() {
     94                if (isFitting.checked) {
     95                    fittingDefaultEnabled.removeAttribute('disabled');
     96                } else onFittingOff();
     97            }
     98            if (!isFitting.checked) onFittingOff();
     99            fittingDefaultEnabled.onchange = function() {
     100                if (fittingDefaultEnabled.checked && !isFitting.checked) fittingDefaultEnabled.checked = false;
     101            }
     102        }
     103
     104        //Warehouses
     105        const isSavePermitted = () => {
     106            let isPermitted = true;
     107            document.querySelectorAll('.ctpt_warehouse').forEach( wh => {
     108                let isValid = true;
     109                if (wh.querySelector('.wh_name_fs input').value.length == 0) {
     110                    isValid = false;
     111                    wh.querySelector('.wh_name_fs input').classList.add(errClass);
     112                }
     113
     114                if (wh.querySelector('.ctpt_wh_active input').checked) {
     115                    if (wh.querySelector('.wh_coords input:first-child').value.length == 0) {
     116                        wh.querySelector('.wh_coords input:first-child').classList.add(errClass);
     117                        isValid = false;
     118                    }
     119                    if (wh.querySelector('.wh_coords input:last-child').value.length == 0) {
     120                        wh.querySelector('.wh_coords input:last-child').classList.add(errClass);
     121                        isValid = false;
     122                    }
     123                    if (wh.querySelector('.wh_cityid input').value.length == 0) {
     124                        isValid = false;
     125                        wh.querySelector('.wh_cityid input').classList.add(errClass);
     126                    }
     127                    if (wh.querySelector('.wh_cityzip input').value.length == 0) {
     128                        isValid = false;
     129                        wh.querySelector('.wh_cityzip input').classList.add(errClass);
     130                    }
     131                    if (wh.querySelector('.wh_senderid input').value.length == 0) {
     132                        isValid = false;
     133                        wh.querySelector('.wh_senderid input').classList.add(errClass);
     134                    }
     135                }
     136                if (wh.querySelector('.wh_poa_enable input').checked) {
     137                    if (wh.querySelector('.wh_poa_fio input').value.length == 0) {
     138                        isValid = false;
     139                        wh.querySelector('.wh_poa_fio input').classList.add(errClass);
     140                    }
     141                    if (wh.querySelector('.wh_poa_p_ser input').value.length == 0) {
     142                        isValid = false;
     143                        wh.querySelector('.wh_poa_p_ser input').classList.add(errClass);
     144                    }
     145                    if (wh.querySelector('.wh_poa_p_num input').value.length == 0) {
     146                        isValid = false;
     147                        wh.querySelector('.wh_poa_p_num input').classList.add(errClass);
     148                    }
     149                    if (wh.querySelector('.wh_poa_p_date input').value.length == 0) {
     150                        isValid = false;
     151                        wh.querySelector('.wh_poa_p_date input').classList.add(errClass);
     152                    }
     153                    if (wh.querySelector('.wh_poa_p_mail input').value.length == 0) {
     154                        isValid = false;
     155                        wh.querySelector('.wh_poa_p_mail input').classList.add(errClass);
     156                    }
     157                }
     158
     159                if (!isValid) {
     160                    isPermitted = false;
     161                }
     162                setTimeout( () => {
     163                    wh.querySelectorAll('input').forEach( el => el.classList.remove(errClass) );
     164                }, 20000 );
     165            } );
     166            return isPermitted;
     167        }
     168
     169        if (document.querySelector('#ctpt_new_wh') != null)
     170        document.querySelector('#ctpt_new_wh').onclick = e => {
     171            e.preventDefault();
     172            if (isSavePermitted()) {
     173                document.querySelector('input[name=is_new_wh]').value = 'Y';
     174                document.querySelector('.woocommerce-save-button').removeAttribute('disabled');
     175                document.querySelector('.woocommerce-save-button').click();
     176            } else {
     177                alert('Вначале необходимо заполнить необходимые данные по складам.');
     178                e.preventDefault();
     179                e.stopPropagation();
     180                return false;
     181            }
     182        }
     183
     184        let isDelFunction = false;
     185        if (document.querySelectorAll('#ctpt_wh_delete') != null)
     186        document.querySelectorAll('#ctpt_wh_delete').forEach(el => {
     187            el.onclick = (e) => {
     188                e.preventDefault();
     189                if (confirm("Действительно удалить склад?\nЭто действие необратимо.")) {
     190                    isDelFunction = true;
     191                    document.querySelector('input[name=is_wh_del]').value = el.attributes['wh_id'].value;
     192                    document.querySelector('.woocommerce-save-button').removeAttribute('disabled');
     193                    document.querySelector('.woocommerce-save-button').click();
     194                }
     195            }
     196        });
     197
     198        if (document.querySelector('#mainform') != null)
     199        document.querySelector('#mainform').onsubmit = e => {
     200            if (!isSavePermitted() && !isDelFunction) {
     201                e.preventDefault();
     202                setTimeout(() => {
     203                    document.querySelectorAll('.is-busy').forEach(el => {
     204                        el.classList.remove('is-busy');
     205                    });
     206                },1000);
     207                alert('Вначале необходимо заполнить данные по складам.');
     208                return false;
     209            }
     210        }
     211
     212        function bindWhTriggers() {
     213            document.querySelectorAll('.ctpt_wh_select_dlv_type').forEach( e => {
     214                const inp = e.parentNode.querySelector('.ctpt_wh_select_dlv_code');
     215                const s = e.querySelector('select');
     216                s.onchange = () => {
     217                    if (s.value === 'door') {
     218                        inp.classList.add('hid');
     219                    } else {
     220                        inp.classList.remove('hid');
     221                    }
     222                }
     223                if (s.value === 'warehouse') inp.classList.remove('hid');
     224            } );
     225
     226            //Проверка заполнения координат...
     227            document.querySelectorAll('.wh_coords').forEach(e=> {
     228                e.querySelectorAll('input').forEach(t => {
     229                    t.onchange = () => {
     230                        let r = /^([0-9]){0,2}(\.){1}([0-9]){1,10}$/;
     231                        t.value = t.value.replaceAll(',', '.');
     232                        if (!r.test(t.value)) {
     233                            t.classList.add(errClass)
     234                        } else {
     235                            t.classList.remove(errClass)
     236                        }
     237                    }
     238                });
     239            });
     240            //Проверка заполнения числовых значений
     241            document.querySelectorAll('.wh_digits').forEach(e=> {
     242                const t = e.querySelector('input');
     243                t.onchange = () => {
     244                    let r = /^([0-9]*)$/;
     245                    if (!r.test(t.value)) t.value = '';
     246                }
     247            });
     248
     249            document.querySelectorAll('.wh_amount').forEach(e=>{
     250                const t = e.querySelector('input');
     251                t.onchange = () => {
     252                    let r = /^([0-9]){0,7}(\.){0,1}([0-9]){0,2}$/;
     253                    t.value = t.value.replaceAll(',', '.');
     254                    if (!r.test(t.value)) t.value = '';
     255                }
     256            });
     257            document.querySelectorAll('.wh_poa_p_ser').forEach(e=>{
     258                const t = e.querySelector('input');
     259                t.onchange = () => {
     260                    let r = /^[0-9]{4}$/;
     261                    if (!r.test(t.value)) t.value = '';
     262                }
     263            });
     264            document.querySelectorAll('.wh_poa_p_num').forEach(e=>{
     265                const t = e.querySelector('input');
     266                t.onchange = () => {
     267                    let r = /^[0-9]{6}$/;
     268                    if (!r.test(t.value)) t.value = '';
     269                }
     270            });
     271            document.querySelectorAll('.wh_poa_p_date').forEach(e=>{
     272                const t = e.querySelector('input');
     273                t.onchange = () => {
     274                    let r = /^([0-9]{2})(\.)([0-9]{2})(\.)([0-9]{4})$/;
     275                    if (!r.test(t.value)) t.value = '';
     276                    if (t.value.length > 10) t.value = '';
     277                }
     278            });
     279            document.querySelectorAll('.wh_poa_p_mail').forEach(e=>{
     280                const t = e.querySelector('input');
     281                t.onchange = () => {
     282                    let r = /^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$/;
     283                    if (!r.test(t.value)) t.value = '';
     284                }
     285            });
     286        }
     287        bindWhTriggers();
    126288
    127289    });
  • catapultodelivery/trunk/assets/js/send_panel.js

    r3417476 r3444321  
    1 const cseWarnMsg = document.querySelector('.ctpt_cse_warn'),
    2     suid = window.ctptData.suid,
    3     orderId = window.ctptData.orderId,
    4     operator = window.ctptData.operator,
    5     goodsPrice = window.ctptData.goodsPrice,
    6     shippingPrice = window.ctptData.shippingPrice,
    7     isCod = window.ctptData.isCod,
    8     codAmount = window.ctptData.codAmount,
    9     isInsured = window.ctptData.isEnsurance,
    10     isCSE = operator === 'cse';
     1const cseWarnMsg = document.querySelector('.ctpt_cse_warn')
     2    ,suid = window.ctptData.suid
     3    ,orderId = window.ctptData.orderId
     4    ,operator = window.ctptData.operator
     5    ,goodsPrice = window.ctptData.goodsPrice
     6    ,shippingPrice = window.ctptData.shippingPrice
     7    ,ratePrice = window.ctptData.ratePrice
     8    ,isCod = window.ctptData.isCod
     9    ,codAmount = window.ctptData.codAmount
     10    ,isInsured = window.ctptData.isEnsurance
     11    ,isCSE = operator === 'cse'
     12    ,cData = window.ctptData.cargoData
     13    ,basePrice = window.ctptData.basePrce
     14    ,isFitting = window.ctptData.isFitting
     15    ,isSingleProd = window.ctptData.isProductSingle
     16    ,isPR = window.ctptData.isPR
     17    ,insuranceVal = window.ctptData.insurance_cost / 100
     18
     19
     20    ,orderPaidCheckbox = document.getElementById('ctpt_isBeznal')
     21    ,needInsuranceCheckbox = document.getElementById('ctpt_needInsurance')
     22    ,deliveryPaySideCheckbox = document.getElementById('ctpt_deliveryPaySide')
     23    ,fittingCheckbox = document.getElementById('ctpt_is_fitting')
     24    ,partialDedemptionCheckbox = document.getElementById('ctpt_is_pr')
     25    ,insuranceValueInput = document.getElementById('ctpt_insuranceValue')
     26    ,sumToPay = document.getElementById('ctpt_sumToPay')
     27    //,cseWarn = document.querySelector('.ctpt_warnempty')
     28
     29    ,whSelect = document.getElementById('ctpt_adm_selected_wh')
     30;
    1131
    1232if (isCSE) cseWarnMsg.classList.remove('hide');
     
    4262    frm.append('ctpt_buyerDoorNumber', document.querySelector('input[name=ctpt_buyerDoorNumber]').value);
    4363    frm.append('ctpt_comment', document.querySelector('textarea[name=ctpt_comment]').value);
    44     frm.append('ctpt_needInsurance', document.querySelector('input[name=ctpt_needInsurance]').checked ? 'Y' : 'N' );
    45     frm.append('ctpt_insuranceValue', document.querySelector('input[name=ctpt_insuranceValue]').value);
    46     frm.append('ctpt_isBeznal', document.querySelector('input[name=ctpt_isBeznal]').checked ? 'Y' : 'N' );
    47     frm.append('ctpt_sumToPay', document.querySelector('input[name=ctpt_sumToPay]').value);
    48     frm.append('ctpt_deliveryPaySide', document.querySelector('input[name=ctpt_deliveryPaySide]').checked ? 'Y' : 'N' );
     64    frm.append('ctpt_needInsurance', needInsuranceCheckbox.checked ? 'Y' : 'N' );
     65    frm.append('ctpt_insuranceValue', insuranceValueInput.value);
     66    frm.append('ctpt_isBeznal', orderPaidCheckbox.checked ? 'Y' : 'N' );
     67    frm.append('ctpt_sumToPay', sumToPay.value);
     68    frm.append('ctpt_deliveryPaySide', deliveryPaySideCheckbox.checked ? 'Y' : 'N' );
     69    frm.append('ctpt_is_fitting', fittingCheckbox.checked ? 'Y' : 'N' );
     70    frm.append('ctpt_is_pr', partialDedemptionCheckbox.checked ? 'Y' : 'N' );
    4971
    5072    const response= await fetch('/?rest_route=/catapultodelivery/ordersend', {
     
    97119            order_id: orderId,
    98120            isEmpty: false,
     121            insurance: window.Ctpt_widgetParams.need_insurance,
     122            pr: window.Ctpt_widgetParams.is_partial_redemption,
    99123        };
    100124        sendVariant(Item);
     
    108132            order_id: orderId,
    109133            isEmpty: false,
     134            insurance: window.Ctpt_widgetParams.need_insurance,
     135            pr: window.Ctpt_widgetParams.is_partial_redemption,
    110136        };
    111137        if (typeof(Item['Variant']) !== 'undefined') {
     
    117143}
    118144
     145whSelect.onchange = ev => {
     146    const selectedWhId = Number(ev.target.value);
     147    if (selectedWhId != window.ctptData.selectedwh) {
     148        if (confirm('Вы уверены, что хотите изменить склад? Если да, то будет запущен выбор способа доставки для выбранного склада.')) {
     149            for (let i in window.ctptData.warehouses) {
     150                if (window.ctptData.warehouses[i].id == selectedWhId) {
     151                    window.Ctpt_widgetParams.sender_contact_params.locality_id = window.ctptData.warehouses[i].lid;
     152                    window.Ctpt_widgetParams.sender_contact_params.zip = window.ctptData.warehouses[i].zip;
     153                    window.Ctpt_widgetParams.sender_contact_params.cityFrom = window.ctptData.warehouses[i].city;
     154                    window.Ctpt_widgetParams.warehouseId = selectedWhId;
     155                    document.getElementById('ctpt_reselect').click();
     156                }
     157            }
     158        }
     159    }
     160}
     161
    119162document.querySelector('#ctpt_reselect').onclick = e => {
    120163    e.preventDefault();
    121164    window.Ctpt_widgetParams.onSelectPvzItem = selectPVZItem;
    122165    window.Ctpt_widgetParams.onSelectCourierItem = selectCourierItem;
    123     window.Ctpt_widgetParams.need_insurance = document.getElementById('ctpt_needInsurance').checked;
    124     window.Ctpt_widgetParams.insured_value = Number(document.getElementById('ctpt_insuranceValue').value);
     166    window.Ctpt_widgetParams.need_insurance = needInsuranceCheckbox.checked;
     167    window.Ctpt_widgetParams.insured_value = Number(insuranceValueInput.value);
    125168    if (isNaN(window.Ctpt_widgetParams.insured_value)) window.Ctpt_widgetParams.insured_value = 0;
     169    window.Ctpt_widgetParams.is_fitting = fittingCheckbox.checked;
     170    window.Ctpt_widgetParams.fitting_default = fittingCheckbox.checked;
     171    window.Ctpt_widgetParams.is_partial_redemption = partialDedemptionCheckbox.checked;
     172
     173    if (typeof(window.ctptData.w_geo_data_empty_message) != 'string') window.ctptData.w_geo_data_empty_message = '';
     174    if (typeof(window.ctptData.w_ws_api_domain) != 'string') window.ctptData.w_ws_api_domain = '';
     175
     176    if (window.ctptData.w_geo_data_empty_message != '') window.Ctpt_widgetParams.geo_data_empty_message = window.ctptData.w_geo_data_empty_message;
     177    if (window.ctptData.w_ws_api_domain != '') window.Ctpt_widgetParams.ws_api_domain = window.ctptData.w_ws_api_domain;
     178
     179    //cargoes
     180    window.Ctpt_widgetParams.cargo = [];
     181    for (let i in cData) {
     182        window.Ctpt_widgetParams.cargo.push({
     183            quantity: 1,
     184            height: cData[i].height,
     185            length: cData[i].length,
     186            width: cData[i].width,
     187            weight: cData[i].weight,
     188            cargo_comment: cData[i].descr,
     189
     190            crg_id: cData[i].id,
     191            ord: cData[i].ord,
     192        });
     193    }
     194
     195    console.log('widget_init_params', window.Ctpt_widgetParams);
     196
    126197    if (!window.CatapultoWidget) {
    127198        window.CatapultoWidget = new CatapultoWidget2(window.Ctpt_widgetParams);
     
    134205}
    135206
    136 const onInsuranceChange = () => {
    137     const
    138         needInsurance = document.getElementById('ctpt_needInsurance'),
    139         insuranseVal = document.getElementById('ctpt_insuranceValue');
    140 
    141     if (needInsurance.checked) insuranseVal.readOnly = false;
    142     else insuranseVal.readOnly = true;
    143     onPayChange(false);
    144 }
    145 const onDeliveryPaySideChange = () => {
    146     const paySide = document.getElementById('ctpt_deliveryPaySide');
    147     if (paySide.checked && paySide.disabled) paySide.checked = false;
    148     if (paySide.checked) onPayChange();
    149     else document.getElementById('ctpt_sumToPay').value = goodsPrice;
    150 }
    151 
    152 const onPayChange = (changeDeliveryPaySide = true) => {
    153     const
    154         needInsurance = document.getElementById('ctpt_needInsurance'),
    155         isBeznal = document.getElementById('ctpt_isBeznal'),
    156         paySide = document.getElementById('ctpt_deliveryPaySide'),
    157         toPay = document.getElementById('ctpt_sumToPay');
    158 
    159     if (isBeznal.checked) {
    160         toPay.value = '0';
    161 
    162         paySide.checked = false;
    163         paySide.disabled = true;
    164 
     207needInsuranceCheckbox.checked = window.ctptData.isEnsurance;
     208
     209
     210jQuery('#ctpt_cargoes').click(function(e){
     211    e.preventDefault();
     212    jQuery('.ctpt_cargowin,.ctpt_cargowinbg').addClass('sh');
     213    return false;
     214});
     215jQuery('.ctpt_cargowin_close').click(function(){
     216    jQuery('.ctpt_cargowin,.ctpt_cargowinbg').removeClass('sh');
     217});
     218
     219//////////////// CALC EVENTS ////////////////////////
     220
     221//страховка
     222needInsuranceCheckbox.onchange = () => {
     223    if(!needInsuranceCheckbox.checked) {
     224        insuranceValueInput.setAttribute('disabled', 'disabled');
     225    } else {
     226        insuranceValueInput.removeAttribute('disabled');
     227    }
     228
     229    calculate();
     230};
     231//примерка
     232fittingCheckbox.onchange = () => {
     233    if (fittingCheckbox.checked) {
     234        partialDedemptionCheckbox.checked = true;
     235        partialDedemptionCheckbox.setAttribute('disabled', 'disabled');
     236    } else {
     237        partialDedemptionCheckbox.removeAttribute('disabled');
     238    }
     239    if (isSingleProd) {
     240        partialDedemptionCheckbox.checked = false;
     241        partialDedemptionCheckbox.setAttribute('disabled', 'disabled');
     242    }
     243
     244    calculate();
     245}
     246//частичный выкуп
     247partialDedemptionCheckbox.onchange = () => {
     248    calculate();
     249}
     250//заказ оплачен
     251orderPaidCheckbox.onchange = () => {
     252    const maxDlvPrice = Math.min(Number(basePrice), Number(ratePrice));
     253    if (
     254        !orderPaidCheckbox.checked
     255        && maxDlvPrice > 0
     256    ) {
     257        deliveryPaySideCheckbox.checked = true;
     258        deliveryPaySideCheckbox.removeAttribute('readonly');
     259    } else {
     260        deliveryPaySideCheckbox.checked = false;
     261        deliveryPaySideCheckbox.setAttribute('readonly', 'readonly');
     262    }
     263
     264    calculate();
     265}
     266//плательщик
     267deliveryPaySideCheckbox.onchange = () => {
     268    if (deliveryPaySideCheckbox.checked && (deliveryPaySideCheckbox.attributes.getNamedItem('readonly') !== null)) {
     269        deliveryPaySideCheckbox.checked = false;
     270    }
     271
     272    calculate();
     273}
     274
     275calculate();
     276
     277//////////////// CALCPRICE ////////////////////////
     278//calculate delivery cost
     279function calculate() {
     280    const productsPrice = parseFloat(goodsPrice)
     281        ,baseDLVPrice = parseFloat(basePrice)
     282        ,baseRatePrice = parseFloat(ratePrice)
     283        ,maxDlvPrice = Math.min(baseDLVPrice, baseRatePrice)
     284        //,priceLabel = $('#'+t.moduleLbl+'hidLabel_delivery_sum')
     285    ;
     286    let dlvSum = baseDLVPrice;
     287
     288    sumToPay.setAttribute('readonly', 'readonly');
     289
     290    //calc delivery cost..
     291    //if (s.isSending) priceLabel.html(dlvSum);
     292    if (maxDlvPrice > 0) {
     293        if (insuranceValueInput.checked) dlvSum += Math.ceil(productsPrice * insuranceVal);
     294        //Additinal services
     295        dlvSum += calcAdditionalServiceCost();
     296        //if (s.isSending) priceLabel.html(dlvSum);
     297    }
     298
     299    if (orderPaidCheckbox.checked) {
     300        sumToPay.value = 0;
     301        //priceLabel.html(baseDLVPrice);
     302
     303        deliveryPaySideCheckbox.checked = false;
     304        deliveryPaySideCheckbox.setAttribute('readonly', 'readonly');
    165305        if (isCSE) cseWarnMsg.classList.add('hide');
    166306    } else {
    167         let insuranseValue = Number(document.getElementById('ctpt_insuranceValue').value),
    168             sumToPay = parseFloat(goodsPrice);
    169         if (isNaN(insuranseValue)) insuranseValue = 0;
    170         const insValue = Math.ceil(parseFloat(insuranseValue) * 0.01);
    171         if (parseFloat(shippingPrice) == 0) {
    172             paySide.checked = false;
    173             changeDeliveryPaySide = false;
    174             paySide.disabled = true;
    175         }
    176         if ( changeDeliveryPaySide || paySide.checked ) {
    177             if ( !isInsured && needInsurance.checked ) sumToPay += insValue;
    178             if ( isInsured && !needInsurance.checked ) sumToPay -= insValue;
    179 
    180             sumToPay += parseFloat(shippingPrice);
    181         }
    182         toPay.value = sumToPay;
    183         if (changeDeliveryPaySide || parseFloat(shippingPrice) > 0) {
    184             paySide.checked = true;
    185             paySide.disabled = false;
    186         }
    187         if (isCSE) cseWarnMsg.classList.remove('hide');
    188     }
    189 
    190 }
    191 
     307        let fullSum = productsPrice;
     308        sumToPay.removeAttribute('readonly');
     309        /*if (s.isSending)*/ sumToPay.value = fullSum;
     310
     311        if (maxDlvPrice > 0) {
     312
     313            if (deliveryPaySideCheckbox.checked) {
     314
     315                fullSum += baseDLVPrice;
     316                if (needInsuranceCheckbox.checked) fullSum += Math.ceil(productsPrice * insuranceVal);
     317
     318                fullSum += calcAdditionalServiceCost();
     319            }
     320
     321            /*if (s.isSending)*/ sumToPay.value = fullSum;
     322
     323            deliveryPaySideCheckbox.removeAttribute('readonly');
     324            //cseWarn.css('display','block');
     325            if (isCSE) cseWarnMsg.classList.remove('hide');
     326        }
     327
     328    }
     329}
     330
     331function calcAdditionalServiceCost() {
     332    let i, adtCost, cost = 0, dlvs = window.ctptData.services;
     333    try {
     334        dlvs = JSON.parse(dlvs);
     335    } catch (e) {
     336        alert('Не могу распознать сервисы. Выберите новый вариант расчета.');
     337        return 0;
     338    }
     339
     340    for (i in dlvs) {
     341        switch (dlvs[i]['name']) {
     342            case 'cod_amount':
     343                if (deliveryPaySideCheckbox.checked) {
     344                    adtCost = Number(dlvs[i]['cost']);
     345                    if (isNaN(adtCost)) adtCost = 0;
     346                    cost += adtCost;
     347                }
     348                break;
     349            case 'fitting_amount':
     350                if (fittingCheckbox.checked) {
     351                    adtCost = Number(dlvs[i]['cost']);
     352                    if (isNaN(adtCost)) adtCost = 0;
     353                    cost += adtCost;
     354                }
     355                break;
     356            case 'partial_redemption_amount':
     357                if (partialDedemptionCheckbox.checked) {
     358                    adtCost = Number(dlvs[i]['cost']);
     359                    if (isNaN(adtCost)) adtCost = 0;
     360                    cost += adtCost;
     361                }
     362                break;
     363        }
     364    }
     365    return cost;
     366}
     367
     368//////////////// EVENTS ////////////////////////
    192369document.getElementById('ctpt_sendorder').onclick = sendOrder;
    193 document.getElementById('ctpt_needInsurance').onchange = onInsuranceChange;
    194 document.getElementById('ctpt_deliveryPaySide').onchange = onDeliveryPaySideChange;
    195 document.getElementById('ctpt_isBeznal').onchange = onPayChange;
    196 onPayChange();
    197 
    198 if (window.ctptData.isEnsurance) {
    199     document.getElementById('ctpt_needInsurance').checked = true;
    200 } else {
    201     document.getElementById('ctpt_insuranceValue').readOnly = true;
    202 }
     370if (isFitting) fittingCheckbox.checked = true;
     371let isPRDisabled = false
     372    ,isPRChecked = false;
     373if (!isSingleProd && ( isFitting || isPR ) ) isPRChecked = true;
     374if ( (/*isPRChecked ||*/ isFitting) || isSingleProd ) isPRDisabled = true;
     375partialDedemptionCheckbox.checked = isPRChecked;
     376if (isPRDisabled) partialDedemptionCheckbox.setAttribute('disabled', 'disabled');
     377
     378calculate();
     379
     380//////////////// CARGO ////////////////////////
     381const tbl_header = `<tr>
     382                        <th>Габариты (мм)</th>
     383                        <th>Вес (г)</th>
     384                        <th>Кол-во</th>
     385                        <th>Артикул</th>
     386                        <th>Стоимость</th>
     387                    </tr>`;
     388const copyObj = function(obj){
     389    return JSON.parse(JSON.stringify(obj));
     390};
     391
     392const cargoes = [];
     393// Заполнение карги здесь...
     394for (let i in cData) {
     395    const crg = {
     396        id: cData[i].id,
     397        cargoId: cData[i].ccargo_id,
     398        orderId: cData[i].ord,
     399        length: cData[i].length,
     400        width: cData[i].width,
     401        height: cData[i].height,
     402        weight: cData[i].weight,
     403        volume: 0,
     404        items: [],
     405    };
     406    for (let j in cData[i].items) {
     407        crg.items.push({
     408            id: cData[i].items[j].id,
     409            productId: cData[i].items[j].id, //////////
     410            variantId: cData[i].items[j].fields.sku,
     411            quantity: cData[i].items[j].quantity,
     412            price: {
     413                amount: cData[i].items[j].price.amount,
     414                currency: cData[i].items[j].price.currency,
     415            },
     416            name: cData[i].items[j].name,
     417            articul: cData[i].items[j].articul,
     418            weight: cData[i].items[j].weight,
     419            length: cData[i].items[j].length,
     420            width: cData[i].items[j].width,
     421            height: cData[i].items[j].height,
     422            dimEmpty: cData[i].items[j].fields.dimEmpty === true,
     423        });
     424    }
     425    cargoes.push(crg);
     426}
     427
     428let crgdata = copyObj(cargoes); //объект для модификации...
     429
     430function onReady() {
     431    closeMoverWin();
     432    //generate saved cargo html
     433    let i, html = '', htmlinfo = '',isFirst = true;
     434    for (i in crgdata) {
     435        html += addCargo(crgdata[i], Number(i)+1, isFirst);
     436        htmlinfo += addCargoInfo(crgdata[i], Number(i)+1);
     437        isFirst = false;
     438    }
     439    jQuery('.ctpt_cargo_table .cargoes').html(html);
     440    jQuery('.cargo_gabs_block_content').html(htmlinfo);
     441    rebindEvents();
     442}
     443
     444function addCargo(cargo, crgNum = 0, isFirst = false) {
     445    let i, cargo_items='', name='', frst = isFirst ? 1 : 0;
     446    if (crgNum > 0) name = 'Место ' + Number(crgNum);
     447    //gen_html_items
     448    for (i in cargo.items) {
     449        let itm_id = cargo.items[i].id,
     450            itm_prodid = cargo.items[i].productId,
     451            itm_varid = cargo.items[i].variantId,
     452            itm_name = cargo.items[i].name,
     453            itm_art = cargo.items[i].articul,
     454            itm_l = cargo.items[i].length,
     455            itm_w = cargo.items[i].width,
     456            itm_h = cargo.items[i].height,
     457            itm_wei = cargo.items[i].weight,
     458            itm_qty = cargo.items[i].quantity,
     459            itm_price = cargo.items[i].price.amount,
     460            itm_empty = cargo.items[i].dimEmpty ? `<tr class="ctpt_crg_itm_warn" i="${itm_id}"><td colspan="5"><p>Внимание! Габариты установлены по умолчанию. Проверьте габариты!</p></td></tr>` : '';
     461        cargo_items += `<tr class="ctpt_crg_itm_nm" i="${itm_id}"><td colspan="5" class="gds_name">${itm_name}</td></tr>
     462                    <tr class="ctpt_crg_itm" i="${itm_id}" pi="${itm_prodid}" vi="${itm_varid}" q="${itm_qty}">
     463                        <td>
     464                            <div class="gabs_wr">
     465                                <input class="gds_l" type="text" value="${itm_l}" />
     466                                <span>X</span>
     467                                <input class="gds_w" type="text" value="${itm_w}" />
     468                                <span>X</span>
     469                                <input class="gds_h" type="text" value="${itm_h}" />
     470                            </div>
     471                        </td>
     472                        <td>
     473                            <input class="gds_wei" type="text" value="${itm_wei}" />
     474                        </td>
     475                        <td>
     476                            <div class="gds_cnt">
     477                                <p>${itm_qty}</p>
     478                                <div class="move_ico"></div>
     479                            </div>
     480                        </td>
     481                        <td>
     482                            <input class="gds_art" type="text" value="${itm_art}" />
     483                        </td>
     484                        <td>
     485                            <div class="gds_price">
     486                                <p>${itm_price}</p>
     487                            </div>
     488                        </td>
     489                    </tr>
     490                    ${itm_empty}
     491                    <tr class="ctpt_crg_itm_ln" i="${itm_id}"><td class="line" colspan="5"></td></tr>`;
     492    }
     493    // <p class="crg_name">${name}</p>
     494    return `<div class="cargo" i="${cargo.id}" crgid="${cargo.cargoId}" frst="${frst}">
     495                <div class="close"></div>
     496                <div class="hdr">
     497                    <p class="crg_name">${name}</p>
     498                    <div class="left">
     499                        <div class="cargo_gabs">
     500                            <p>Габариты (мм)</p>
     501                            <div class="gabs_wr">
     502                                <input class="cargo_l" type="text" value="${cargo.length}" />
     503                                <span>X</span>
     504                                <input class="cargo_w" type="text" value="${cargo.width}" />
     505                                <span>X</span>
     506                                <input class="cargo_h" type="text" value="${cargo.height}" />
     507                            </div>
     508                        </div>
     509                        <div class="cargo_wei">
     510                            <p>Вес (г)</p>
     511                            <div class="field_wr">
     512                                <input class="cargo_wei" type="text" value="${cargo.weight}" />
     513                            </div>
     514                        </div>
     515                    </div>
     516                    <div class="left">
     517                        <div class="ctpt_btn ctpt_calc_cargo_gabs">Рассчитать по размерам товаров</div>
     518                        <div class="ctpt_btn ctpt_calc_cargo_wei">Рассчитать по весу товаров</div>
     519                    </div>
     520                </div>
     521                <table class="cargo_goods">${tbl_header}${cargo_items}</table>
     522            </div>`;
     523}
     524function addCargoInfo(cargo, crgNum = 0) {
     525    let name='';
     526    if (crgNum > 0) name = 'Место ' + Number(crgNum);
     527    return `<p class="cnm"><b>${name}</b></p>
     528    <p><b>Размеры (мм):</b> ${cargo.length} x ${cargo.width} x ${cargo.height}</p>
     529    <p><b>Вес (г):</b> ${cargo.weight}</p>`;
     530}
     531
     532function addNewCargo() {
     533    //Проверяем - есть ли у нас грузоместа с незаполненными товарами? Если есть - не даем создавать грузоместо
     534    for (let i in crgdata) {
     535        if (crgdata[i].items.length == 0) {
     536            alert('Уже есть грузоместо для заполнения товаров.');
     537            return false;
     538        }
     539    }
     540
     541    let newCargo = {
     542        id: Date.now(),
     543        cargoId: 0,
     544        orderId: orderId,
     545        length: 0,
     546        width: 0,
     547        height: 0,
     548        weight: 0,
     549        volume: 0,
     550        items: [],
     551    };
     552    crgdata.push(newCargo);
     553    jQuery(addCargo(newCargo, crgdata.length)).appendTo('.ctpt_cargo_table .cargoes');
     554    rebindEvents();
     555    closeMoverWin();
     556}
     557
     558jQuery('.add_new_cargo').click(addNewCargo);
     559
     560function showMoveWindow() {
     561    const th=jQuery(this),t=th.parents('.ctpt_crg_itm'), crg=t.parents('.cargo'), pp=jQuery('.ctpt_move_win');
     562    if (crgdata.length < 2) {
     563        alert('Необходимо создать больше грузомест для перемещения...');
     564        return;
     565    }
     566    let i, cnt = Number(t.attr('q'));
     567    if (cnt === 0) return;
     568    pp.attr('cnt', cnt);
     569    pp.attr('crg_itm', crg.attr('i'));
     570    pp.attr('gds_id', t.attr('i'));
     571    jQuery('.ctpt_move_win select').html('');
     572    jQuery('.ctpt_move_win .place input').val('');
     573    let selects = '';
     574    for (i in crgdata) {
     575        if (Number(crg.attr('i')) == Number(crgdata[i].id)) continue;
     576        const nm = 'Место ' + (Number(i) + 1);
     577        selects += `<option value="${crgdata[i].id}">${nm}</option>`;
     578    }
     579    jQuery('.ctpt_move_win select').html(selects);
     580    if (crg.attr('frst') == '1') {
     581        jQuery('.ctpt_move_win select option:nth-child(2)').prop('selected', true);
     582    }
     583    jQuery('.ctpt_move_win select option:first-child').attr('selected', 'selected');
     584    jQuery('.ctpt_move_win .place p').html(cnt + ' /');
     585    pp.addClass('sh');
     586    pp.css('left', th.offset().left - 160);
     587    pp.css('top', th.offset().top - 170 + jQuery('.ctpt_cargowin')[0].scrollTop - window.pageYOffset );
     588
     589    jQuery('.ctpt_move_win input').focus();
     590}
     591function moverValidate() {
     592    const t=document.querySelector('.ctpt_move_win .place input'), th=jQuery(this);
     593    th.removeClass('err');
     594    t.value = t.value.replace(/\D/g, "");
     595    let vl = Number(t.value), max = jQuery('.ctpt_move_win').attr('cnt');
     596    if (vl > max) {
     597        th.addClass('err');
     598        return false;
     599    }
     600    if (vl == 0) {
     601        th.addClass('err');
     602        return false;
     603    }
     604    return true;
     605}
     606function digitValidate(ev) {
     607    const input = ev.target;
     608    input.value = input.value.replace(/\D/g, "");
     609}
     610function saveGdsValue(ev) {
     611    const input = ev.target, crg_id = jQuery(input).parents('.cargo').attr('i');
     612    let i, vl = Number(input.value);
     613    for (i in crgdata) {
     614        if (crgdata[i].id == crg_id) {
     615            if (input.classList.contains('cargo_l')) crgdata[i].length = vl;
     616            if (input.classList.contains('cargo_w')) crgdata[i].width = vl;
     617            if (input.classList.contains('cargo_h')) crgdata[i].height = vl;
     618            if (input.classList.contains('cargo_wei')) crgdata[i].weight = vl;
     619        }
     620    }
     621}
     622function saveProductValue(ev) {
     623    const
     624        input = ev.target,
     625        crg_id = jQuery(input).parents('.cargo').attr('i'),
     626        gds_id = jQuery(input).parents('.ctpt_crg_itm').attr('i');
     627    let i, j, vl = Number(input.value);
     628    for (i in crgdata) {
     629        if (crgdata[i].id == crg_id) {
     630            for (j in crgdata[i].items) {
     631                if (crgdata[i].items[j].id == gds_id) {
     632                    if (input.classList.contains('gds_l')) crgdata[i].items[j].length = vl;
     633                    if (input.classList.contains('gds_w')) crgdata[i].items[j].width = vl;
     634                    if (input.classList.contains('gds_h')) crgdata[i].items[j].height = vl;
     635                    if (input.classList.contains('gds_wei')) crgdata[i].items[j].weight = vl;
     636                    if (input.classList.contains('gds_art')) crgdata[i].items[j].articul = input.value;
     637                }
     638            }
     639        }
     640    }
     641}
     642
     643function calcWeiForCargo(crg_id) {
     644    let i, j, weight = 0;
     645    for (i in crgdata) {
     646        if (crgdata[i].id == crg_id) {
     647            for (j in crgdata[i].items) {
     648                weight += crgdata[i].items[j].weight * crgdata[i].items[j].quantity;
     649            }
     650            crgdata[i].weight = weight;
     651        }
     652    }
     653    return weight;
     654}
     655
     656function autoWeight(ev) {
     657    const crg = jQuery(ev.target).parents('.cargo'), crg_id = crg.attr('i'), wei_inp = crg.find('.cargo_wei');
     658    wei_inp.val(calcWeiForCargo(crg_id));
     659}
     660async function autoGabs(ev){
     661    const t=jQuery(ev.target), crg_el = t.parents('.cargo'), crg_id = crg_el.attr('i');
     662    let i, crg = [];
     663    for(i in crgdata) {
     664        if (crgdata[i].id == crg_id) {
     665            crg = crgdata[i];
     666            break;
     667        }
     668    }
     669
     670    t.css('visibility', 'hidden');
     671    // Здесь - обработчик для калькуляции данных грузоместа....
     672    let frm = new FormData();
     673    frm.append('crg', JSON.stringify(crg));
     674    const response= await fetch('/?rest_route=/catapultodelivery/cargocalc', {
     675        method: 'POST',
     676        headers: headers,
     677        body: frm,
     678    }), res = await response.json();
     679    if (res.res) {
     680        crg_el.find('.cargo_l').val(res.l);
     681        crg_el.find('.cargo_w').val(res.w);
     682        crg_el.find('.cargo_h').val(res.h);
     683        crg.width = res.w;
     684        crg.length = res.l;
     685        crg.height = res.h;
     686        t.css('visibility', '');
     687    }
     688}
     689
     690function move(crg_from, crg_to, itm_from, cnt) {
     691    //find cargo...
     692    let i,j,from = false, to = false, crgFrom = false, crgTo = false;
     693    for (i in crgdata) {
     694        // findFrom
     695        if (crgdata[i].id == crg_from) {
     696            crgFrom = crgdata[i];
     697            for(j in crgdata[i].items) {
     698                if (crgdata[i].items[j].id == itm_from) {
     699                    from = crgdata[i].items[j];
     700                    crgdata[i].items[j].quantity -= cnt;
     701                    if (crgdata[i].items[j].quantity == 0) {
     702                        crgdata[i].items.splice(j,1);
     703                    }
     704                }
     705            }
     706        }
     707        //findTo
     708        if (crgdata[i].id == crg_to) {
     709            crgTo = crgdata[i];
     710            for(j in crgdata[i].items) {
     711                if (crgdata[i].items[j].id == itm_from) to = crgdata[i].items[j];
     712            }
     713        }
     714    }
     715    if (to === false) {
     716        //create new item
     717        crgTo.items.push({
     718            id: from.id,
     719            productId: from.productId,
     720            variantId: from.variantId,
     721            quantity: cnt,
     722            price: {
     723                amount: from.price.amount,
     724                currency: from.price.currency
     725            },
     726            name: from.name,
     727            articul: from.articul,
     728            weight: from.weight,
     729            length: from.length,
     730            width: from.width,
     731            height: from.height,
     732            dimEmpty: from.dimEmpty,
     733        });
     734    } else {
     735        to.quantity += cnt;
     736    }
     737
     738    calcWeiForCargo(crg_from);
     739    calcWeiForCargo(crg_to);
     740}
     741
     742function deleteCargo(ev) {
     743    const crg_el=jQuery(ev.target).parent(),
     744        first_crg_id = jQuery('.ctpt_cargo_table .cargo:first-child').attr('i'),
     745        second_crg_id = jQuery('.ctpt_cargo_table .cargo:nth-child(2)').attr('i'),
     746        crg_from = crg_el.attr('i');
     747    if (crgdata.length < 2) return false; //нет достаточного кол-ва грузомест
     748    let i, crg_to = first_crg_id;
     749    if (crg_to == crg_from) crg_to = second_crg_id;
     750
     751    crg_el.find('.ctpt_crg_itm').each(function(){
     752        const t=jQuery(this), itmId = t.attr('i'), qty = Number(t.attr('q'));
     753        move(crg_from, crg_to, itmId, qty);
     754    });
     755    //delete empty cargo
     756    for (i in crgdata) {
     757        if (crgdata[i].items.length == 0) crgdata.splice(i,1);
     758    }
     759
     760    onReady();
     761}
     762
     763jQuery('#ctpt_cargoer_del').click(async function(e){
     764    e.preventDefault();
     765    if (confirm('Действительно удалить данные грузомест?')) {
     766        let frm = new FormData();
     767        frm.append('order_id', orderId);
     768        const response= await fetch('/?rest_route=/catapultodelivery/cargoclear', {
     769            method: 'POST',
     770            headers: headers,
     771            body: frm,
     772        }), res = await response.json();
     773        if (res.res && res.res === true) {
     774            alert('Данные грузомест сброшены.')
     775            setTimeout(function(){
     776                window.location.reload();
     777            },1000);
     778        }
     779        if (typeof(res.res) !== 'undefined' && res.res === false) {
     780            let errMsg = 'Произошла неизвестная ошибка. Попробуйте снова.';
     781            switch (res.e) {
     782                case 'NoOrder':
     783                    errMsg = 'Ошибка заказа (заказ не найден)';
     784                    break;
     785            }
     786            jQuery('.rate_update_errors').html(errMsg).css('display','block');
     787        }
     788    }
     789    return false;
     790});
     791
     792jQuery('.ctpt_move_win .place input').keyup(moverValidate);
     793jQuery('.ctpt_move_win .ctpt_btn_green').click(function(){
     794    const valid = moverValidate(), pp=jQuery('.ctpt_move_win');
     795    if (!valid) return;
     796
     797    const crg_from = pp.attr('crg_itm'),
     798        itm_from = pp.attr('gds_id'),
     799        crg_to = pp.find('select').val(),
     800        cnt = Number(pp.find('.place input').val());
     801
     802    if (crg_from == crg_to) return;
     803    move(crg_from, crg_to, itm_from, cnt);
     804    onReady();
     805});
     806
     807function rebindEvents() {
     808    jQuery('.ctpt_cargo_table .move_ico').click(showMoveWindow);
     809    //cargoValsInputs
     810    jQuery('.ctpt_cargo_table .cargo_l').keyup(digitValidate);
     811    jQuery('.ctpt_cargo_table .cargo_w').keyup(digitValidate);
     812    jQuery('.ctpt_cargo_table .cargo_h').keyup(digitValidate);
     813    jQuery('.ctpt_cargo_table .cargo_wei').keyup(digitValidate);
     814    jQuery('.ctpt_cargo_table .cargo_l').blur(saveGdsValue);
     815    jQuery('.ctpt_cargo_table .cargo_w').blur(saveGdsValue);
     816    jQuery('.ctpt_cargo_table .cargo_h').blur(saveGdsValue);
     817    jQuery('.ctpt_cargo_table .cargo_wei').blur(saveGdsValue);
     818
     819    //itemsValsInputs
     820    jQuery('.ctpt_cargo_table .gds_l').keyup(digitValidate);
     821    jQuery('.ctpt_cargo_table .gds_w').keyup(digitValidate);
     822    jQuery('.ctpt_cargo_table .gds_h').keyup(digitValidate);
     823    jQuery('.ctpt_cargo_table .gds_wei').keyup(digitValidate);
     824    jQuery('.ctpt_cargo_table .gds_l').blur(saveProductValue);
     825    jQuery('.ctpt_cargo_table .gds_w').blur(saveProductValue);
     826    jQuery('.ctpt_cargo_table .gds_h').blur(saveProductValue);
     827    jQuery('.ctpt_cargo_table .gds_wei').blur(saveProductValue);
     828    jQuery('.ctpt_cargo_table .gds_art').blur(saveProductValue);
     829
     830    //recalc gabs
     831    jQuery('.ctpt_cargo_table .ctpt_calc_cargo_gabs').click(autoGabs);
     832    jQuery('.ctpt_cargo_table .ctpt_calc_cargo_wei').click(autoWeight);
     833
     834    //delete cargo
     835    jQuery('.ctpt_cargo_table .cargo .close').click(deleteCargo);
     836}
     837
     838function closeMoverWin() {
     839    jQuery('.ctpt_move_win').removeClass('sh').css({left:'',top:''});
     840}
     841
     842jQuery('.ctpt_move_win .close').click(closeMoverWin);
     843
     844jQuery('.ctpt_gdsdata_reset').click(function(){
     845    crgdata = copyObj(cargoes);
     846    onReady();
     847});
     848jQuery('.ctpt_gdsdata_save').click(async function(){
     849    //check data...
     850    let i,j,k,v,isValid = true;
     851    const vars = ['length','width','height','weight'];
     852    for (i in crgdata) {
     853        for (j in vars) {
     854            v = Number(crgdata[i][vars[j]]);
     855            if (isNaN(v)) v = 0;
     856            if (v == 0) isValid = false;
     857        }
     858        for (k in crgdata[i].items) {
     859            for (j in vars) {
     860                v = Number(crgdata[i].items[k][vars[j]]);
     861                if (isNaN(v)) v = 0;
     862                if (v == 0) isValid = false;
     863            }
     864        }
     865    }
     866    if (!isValid) {
     867        alert('Невозможно сохранить габариты. Проверьте данные.')
     868        return;
     869    }
     870
     871    //save new crgdata
     872    let frm = new FormData();
     873    frm.append('order_id', orderId);
     874    frm.append('crg', JSON.stringify(crgdata));
     875    const response= await fetch('/?rest_route=/catapultodelivery/cargosave', {
     876        method: 'POST',
     877        headers: headers,
     878        body: frm,
     879    }), res = await response.json();
     880    if (res.res && res.res === true) {
     881        jQuery('.ctpt_cargo_table, .ctpt_alert').css('display','none');
     882        jQuery('.rate_update_success').css('display','block');
     883
     884        setTimeout(function(){
     885            window.location.reload();
     886        },5000);
     887
     888    }
     889    if (typeof(res.res) !== 'undefined' && res.res === false) {
     890        let errMsg = 'Произошла неизвестная ошибка. Попробуйте снова.';
     891        switch (res.e) {
     892            case 'NoOrder':
     893                errMsg = 'Ошибка заказа (заказ не найден)';
     894                break;
     895            case 'corrupted':
     896                errMsg = 'Данные грузоместа повреждены. Перезагрузите страницу и попробуйте сохранить снова.';
     897                break;
     898        }
     899        jQuery('.rate_update_errors').html(errMsg).css('display','block');
     900    }
     901});
     902
     903document.addEventListener('DOMContentLoaded',onReady);
     904
     905jQuery('.cargo_gabs_block').click(function(e){
     906    const t=jQuery(this), d=jQuery('.cargo_gabs_block_content');
     907    if (t.hasClass('sh')) {
     908        t.removeClass('sh');
     909        d.slideUp();
     910    } else {
     911        t.addClass('sh');
     912        d.slideDown();
     913    }
     914});
     915
     916if (window.ctptData.cargo_valid === true) jQuery('.ctpt_custom_cargo_valid').css('display','none');
     917
     918jQuery('.ctpt_hintlbl').hover(function(){
     919    const el=jQuery(this).parent().find('.ctpt_hint_content');
     920    el.addClass('sh');
     921},function(){
     922    const el=jQuery(this).parent().find('.ctpt_hint_content');
     923    el.removeClass('sh');
     924});
     925
  • catapultodelivery/trunk/assets/js/widget_handler.js

    r3417476 r3444321  
    88                isEmpty: false,
    99                insurance: window.Ctpt_widgetParams.need_insurance,
     10                pr: window.Ctpt_widgetParams.is_partial_redemption,
    1011            };
    1112            if (typeof(Item['Variant']) !== 'undefined') {
     
    2324                isEmpty: false,
    2425                insurance: window.Ctpt_widgetParams.need_insurance,
     26                pr: window.Ctpt_widgetParams.is_partial_redemption,
    2527            };
    2628            sendVariant(Item);
  • catapultodelivery/trunk/build/catapulto-checkout-block-frontend.asset.php

    r3417476 r3444321  
    1 <?php return array('dependencies' => array('jquery', 'lodash', 'react', 'wc-blocks-checkout', 'wc-settings', 'wp-data', 'wp-element'), 'version' => '8fd4e5056a7c48ee2dea');
     1<?php return array('dependencies' => array('jquery', 'lodash', 'react', 'wc-blocks-checkout', 'wc-settings', 'wp-data', 'wp-element'), 'version' => '6622efd779a2848fc955');
  • catapultodelivery/trunk/build/catapulto-checkout-block-frontend.js

    r3417476 r3444321  
    1 (()=>{"use strict";var e={20:(e,t,a)=>{var r=a(609),o=Symbol.for("react.element"),i=Symbol.for("react.fragment"),s=Object.prototype.hasOwnProperty,n=r.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,d={key:!0,ref:!0,__self:!0,__source:!0};function p(e,t,a){var r,i={},p=null,c=null;for(r in void 0!==a&&(p=""+a),void 0!==t.key&&(p=""+t.key),void 0!==t.ref&&(c=t.ref),t)s.call(t,r)&&!d.hasOwnProperty(r)&&(i[r]=t[r]);if(e&&e.defaultProps)for(r in t=e.defaultProps)void 0===i[r]&&(i[r]=t[r]);return{$$typeof:o,type:e,key:p,ref:c,props:i,_owner:n.current}}t.Fragment=i,t.jsx=p,t.jsxs=p},848:(e,t,a)=>{e.exports=a(20)},609:e=>{e.exports=window.React}},t={};const a=window.wc.blocksCheckout,r=window.wp.element,o=window.lodash,i=window.wc.wcSettings;window.wp.data,window.jQuery;var s=function a(r){var o=t[r];if(void 0!==o)return o.exports;var i=t[r]={exports:{}};return e[r](i,i.exports,a),i.exports}(848);const n=JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":3,"name":"catapultodelivery/catapulto-checkout-block","version":"1.0.0","title":"Catapulto Widget","category":"widgets","description":"Adds a Catapulto widget on checkout to allow user select delivery variant.","supports":{"html":false,"align":false,"multiple":false,"reusable":false},"parent":["woocommerce/checkout-shipping-methods-block"],"attributes":{"lock":{"type":"object","default":{"remove":true,"move":true}},"text":{"type":"string","default":""}},"textdomain":"catapultodelivery"}');(0,a.registerCheckoutBlock)({metadata:n,component:({checkoutExtensionData:e,extensions:t,cart:a,validation:n})=>{const d="catapultodelivery",p={isFirstSended:!1,isWidgetRun:!1},[c,l]=(0,r.useState)({isSelected:!1,isPVZ:!1,operator:"",operatorLogo:"",tarif:"",pvz:"",dlvTime:""}),[u,g]=(0,r.useState)(!1),[_,m]=(0,r.useState)(!1),[h,y]=(0,r.useState)(""),[w,f]=(0,r.useState)(!0),[v,S]=(0,r.useState)(0),[k,b]=(0,r.useState)(""),[C,x]=(0,r.useState)(""),[W,R]=(0,r.useState)(""),E={popup_mode:!0,service_path:"",sender_contact_params:{locality_id:"",zip:"",cityFrom:""},dadata_token:"",only_delivery_type:"",startTabMap:!1,delivery_type:"door",day_shift:0,inverse_delivery_type_for_operators:[],location:{address:""},cargo:{weight:0,height:0,length:0,width:0,quantity:1},need_insurance:!1,insured_value:0},[j,D]=(0,r.useState)({services_filter:"",filter_cash:!1,filter_card:!1}),[O,P]=(0,r.useState)(!1),[T,L]=(0,r.useState)(E),{setExtensionData:V}=e,{isTestMode:z,customWss:A,servicePath:F,senderLocalityId:M,senderZip:q,senderCityFrom:I,dadataToken:N,cargoHeight:Z,cargoLength:U,cargoWidth:J,cargoWeight:$,cargoComment:B,insuredValue:H,needInsurance:Q,PSCard:Y,PSCash:G,widgetDeliveryTypes:K,deliveryType:X,dayShift:ee,mapOpenMode:te,inverseOperators:ae,freeDeliveryOperators:re,operatorsSettings:oe,runOnStart:ie,opIcons:se,geoEmptyMessage:ne,freeDlvMinCourier:de,freeDlvMinPVZ:pe}=(0,i.getSetting)(d+"_data"),ce=(0,r.useCallback)((0,o.debounce)((e=>{if(V(d,"ctpt_ratedata",""),V(d,"ctpt_paychanged","true"),!a.cartNeedsShipping)return;const t=e.flatMap((e=>e.shipping_rates)).find((e=>e.selected));if(t&&Object.prototype.hasOwnProperty.call(t,"method_id")&&t.method_id===d){if(S(wc.wcSettings.getSetting("checkoutData").order_id),t.meta_data.length>0){let e={},a={isSelected:!1,isPVZ:!1,operator:"",operatorLogo:"",tarif:"",pvz:"",dlvTime:""},r="";for(let o in t.meta_data)switch(t.meta_data[o].key){case"ctpt_params":a.isPVZ="pvz"===t.meta_data[o].value.rate_type,e.ctpt_params=t.meta_data[o].value;break;case"variant":a.isSelected=!0,a.operator=t.meta_data[o].value.operator,void 0!==se[a.operator]&&(a.operatorLogo=se[a.operator]),a.tarif=t.meta_data[o].value.rate,e.variant=t.meta_data[o].value;break;case"selected":e.selected=t.meta_data[o].value;break;case"Terminal":r=t.meta_data[o].value.address+"#"+t.meta_data[o].value.code,e.Terminal=t.meta_data[o].value;break;case"dadata":e.dadata=t.meta_data[o].value;break;case"rate_param":e.rate_param=t.meta_data[o].value}a.isPVZ&&(a.pvz=r),l(a),V(d,"ctpt_ratedata",JSON.stringify(e)),V(d,"ctpt_paychanged","false")}y(t.method_id),g(!0)}else g(!1)}),1e3),[]),le=()=>{void 0===window.ctptData&&(window.ctptData=p)};(0,r.useEffect)((()=>{le()}),[]),(0,r.useEffect)((()=>{le(),a.isLoading||a.isLoadingRates||ce(a.shippingRates)}),[a.isLoading,a.isLoadingRates,a.shippingRates,a.shippingAddress]),(0,r.useEffect)((()=>{let e="";"string"==typeof a.shippingAddress.state&&a.shippingAddress.state.length>2&&(e+=a.shippingAddress.state+", "),"string"==typeof a.shippingAddress.city&&a.shippingAddress.city.length<=2||b(e+a.shippingAddress.city)}),[a.shippingAddress.city,a.shippingAddress.state]),(0,r.useEffect)((()=>{const e=document.querySelector("#payment-method .wc-block-components-radio-control"),t=document.querySelectorAll("input[name=radio-control-wc-payment-method-options]");if(null==t||null==e)return;const a=e=>{R(e.target.value)};t.forEach((e=>{e.checked&&R(e.value),e.onchange=a})),document.querySelector("#payment-method .wc-block-components-radio-control").addEventListener("DOMSubtreeModified",(()=>{document.querySelectorAll("input[name=radio-control-wc-payment-method-options]").forEach((e=>{e.checked&&R(e.value),e.onchange=a}))}))}),[document.querySelector("input[name=radio-control-wc-payment-method-options]"),document.querySelector("#payment-method .wc-block-components-radio-control")]),(0,r.useEffect)((()=>{let e=Y.includes(W),t=G.includes(W);V(d,"ctpt_paychanged","true"),D(e||t?{services_filter:"NP,COD",filter_cash:t,filter_card:e}:{services_filter:"",filter_cash:!1,filter_card:!1})}),[W]),(0,r.useEffect)((()=>{let e={...E,...j,location:{address:k},service_path:F,sender_contact_params:{locality_id:M,zip:q,cityFrom:I},dadata_token:N,only_delivery_type:K,delivery_type:X,inverse_delivery_type_for_operators:ae,free_delivery_operators:re,operators_settings:oe,day_shift:ee,cargo:{weight:$,height:Z,width:J,length:U,cargo_comment:B,quantity:1},need_insurance:Q,insured_value:H,startTabMap:te,onSelectPvzItem:we,onSelectCourierItem:ye,onRateResponse:me,onPopupClose:()=>{"function"==typeof window.CatapultoWidget.destroy&&window.CatapultoWidget.destroy(),delete window.CatapultoWidget,_e()}};(null!=z?z:"string"==typeof A)&&(e.ws_api_domain=A),ne.length>2&&(e.geo_data_empty_message=ne),de>0&&(e.free_delivery_min_courier=de),pe>0&&(e.free_delivery_min_pvz=pe),L(e),P(!0)}),[j,k]);const[ue,ge]=(0,r.useState)(0),_e=()=>{if(ge(0),window.CatapultoWidget?("function"==typeof window.CatapultoWidget.destroy&&window.CatapultoWidget.destroy(),delete window.CatapultoWidget,window.CatapultoWidget=new CatapultoWidget2(T)):window.CatapultoWidget=new CatapultoWidget2(T),_||m(!0),void 0===window.ctpt_widgetRunned&&(window.ctpt_widgetRunned=!1),!1===window.ctpt_widgetRunned&&ie){let e=!1;for(let t in a.shippingRates[0].shipping_rates)a.shippingRates[0].shipping_rates[t].method_id==d&&a.shippingRates[0].shipping_rates[t].selected&&(e=!0);e&&(window.ctpt_widgetRunned=!0,window.CatapultoWidget.show())}};(0,r.useEffect)((()=>{O&&O&&(ue>0&&clearTimeout(ue),ge(setTimeout(_e,3e3)))}),[T,u]);const me=e=>{void 0!==e.results&&e.results.forEach((e=>{void 0===e.price_orig&&(e.price_orig=e.price)}))},he=e=>{window.CatapultoWidget.hide();const t=window.CatapultoWidget.getData().getVariant();e.dadata=t,e.rate_param=window.CatapultoWidget.getData().RateParams,e.ctpt_params.order_id=wc.wcSettings.getSetting("checkoutData").order_id,e.ctpt_params.isEmpty=!1,e.ctpt_params.insurance=Q,e.ctpt_params.ps=document.querySelector("#payment-method .wc-block-components-radio-control input:checked").value,V(d,"ctpt_ratedata",JSON.stringify(e)),V(d,"ctpt_paychanged","false"),wc.blocksCheckout.extensionCartUpdate({namespace:d,data:e}).then((()=>{let t={isSelected:!0,isPVZ:"pvz"===e.ctpt_params.rate_type,operator:e.variant.operator,operatorLogo:"",tarif:e.variant.rate,pvz:"pvz"===e.ctpt_params.rate_type?e.Terminal.address+"#"+e.Terminal.code:"",dlvTime:""};void 0!==se[t.operator]&&(t.operatorLogo=se[t.operator]),l(t),le(),window.ctptData.isFirstSended||(window.ctptData.isFirstSended=!0,setTimeout((()=>{wc.blocksCheckout.extensionCartUpdate({namespace:d,data:e})}),200))}))},ye=e=>{e&&void 0!==e.variant.id&&(e.ctpt_params={rate_type:"courier",order_id:0},he(e))},we=e=>{e&&void 0!==e.Variant&&(e.ctpt_params={rate_type:"pvz",order_id:0},void 0!==e.Variant&&(e.variant=e.Variant,delete e.Variant),he(e))};return(0,s.jsxs)("div",{className:"wp-block-shipping-catapulto",style:{display:"block"},children:[(0,s.jsx)("input",{type:"hidden",name:"ctpt_hid_cityname"}),u&&(0,s.jsxs)(s.Fragment,{children:[c.isSelected&&(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)("p",{style:{margin:"0"},children:"Способ доставки:"}),(0,s.jsxs)("p",{style:{display:"flex",alignItems:"center",margin:"0"},children:[(0,s.jsx)("b",{style:{paddingRight:"5px"},children:"Оператор: "})," ",c.operator," ",""!=c.operatorLogo&&(0,s.jsx)("img",{style:{width:"60px",marginLeft:"5px"},src:c.operatorLogo})]}),(0,s.jsxs)("p",{style:{margin:"0"},children:[(0,s.jsx)("b",{children:"Тариф: "})," ",c.tarif]}),c.isPVZ&&(0,s.jsxs)("p",{style:{margin:"0"},children:[(0,s.jsx)("b",{children:"ПВЗ: "})," ",c.pvz]})]}),_&&(0,s.jsx)("button",{onClick:e=>{e.preventDefault(),window.CatapultoWidget&&window.CatapultoWidget.show()},style:{height:"40px",width:"220px",background:"#01bd6c",border:"1px solid #01bd6c",borderRadius:"6px",color:"#fff",cursor:"pointer",fontWeight:"700",transition:".5s"},children:"Выбрать способ доставки"})]})]})}})})();
     1(()=>{"use strict";var e={20:(e,t,a)=>{var i=a(609),o=Symbol.for("react.element"),r=Symbol.for("react.fragment"),s=Object.prototype.hasOwnProperty,n=i.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,d={key:!0,ref:!0,__self:!0,__source:!0};function p(e,t,a){var i,r={},p=null,c=null;for(i in void 0!==a&&(p=""+a),void 0!==t.key&&(p=""+t.key),void 0!==t.ref&&(c=t.ref),t)s.call(t,i)&&!d.hasOwnProperty(i)&&(r[i]=t[i]);if(e&&e.defaultProps)for(i in t=e.defaultProps)void 0===r[i]&&(r[i]=t[i]);return{$$typeof:o,type:e,key:p,ref:c,props:r,_owner:n.current}}t.Fragment=r,t.jsx=p,t.jsxs=p},848:(e,t,a)=>{e.exports=a(20)},609:e=>{e.exports=window.React}},t={};const a=window.wc.blocksCheckout,i=window.wp.element,o=window.lodash,r=window.wc.wcSettings;window.wp.data,window.jQuery;var s=function a(i){var o=t[i];if(void 0!==o)return o.exports;var r=t[i]={exports:{}};return e[i](r,r.exports,a),r.exports}(848);const n=JSON.parse('{"$schema":"https://schemas.wp.org/trunk/block.json","apiVersion":3,"name":"catapultodelivery/catapulto-checkout-block","version":"1.0.0","title":"Catapulto Widget","category":"widgets","description":"Adds a Catapulto widget on checkout to allow user select delivery variant.","supports":{"html":false,"align":false,"multiple":false,"reusable":false},"parent":["woocommerce/checkout-shipping-methods-block"],"attributes":{"lock":{"type":"object","default":{"remove":true,"move":true}},"text":{"type":"string","default":""}},"textdomain":"catapultodelivery"}');(0,a.registerCheckoutBlock)({metadata:n,component:({checkoutExtensionData:e,extensions:t,cart:a,validation:n})=>{const d="catapultodelivery",p={isFirstSended:!1,isWidgetRun:!1},[c,l]=(0,i.useState)({isSelected:!1,isPVZ:!1,operator:"",operatorLogo:"",tarif:"",pvz:"",dlvTime:""}),[u,g]=(0,i.useState)(!1),[m,_]=(0,i.useState)(!1),[h,w]=(0,i.useState)(""),[y,f]=(0,i.useState)(!0),[v,S]=(0,i.useState)(0),[k,b]=(0,i.useState)(""),[C,x]=(0,i.useState)(""),[W,R]=(0,i.useState)(""),E={popup_mode:!0,service_path:"",sender_contact_params:{locality_id:"",zip:"",cityFrom:""},dadata_token:"",only_delivery_type:"",startTabMap:!1,delivery_type:"door",day_shift:0,inverse_delivery_type_for_operators:[],location:{address:""},cargo:{weight:0,height:0,length:0,width:0,quantity:1},need_insurance:!1,insured_value:0},[j,D]=(0,i.useState)({services_filter:"",filter_cash:!1,filter_card:!1}),[O,P]=(0,i.useState)(!1),[T,L]=(0,i.useState)(E),{setExtensionData:V}=e,{isTestMode:A,customWss:z,servicePath:F,senderLocalityId:M,senderZip:q,senderCityFrom:I,dadataToken:N,cargoHeight:Z,cargoLength:U,cargoWidth:J,cargoWeight:$,cargoComment:B,insuredValue:H,needInsurance:Q,PSCard:Y,PSCash:G,widgetDeliveryTypes:K,deliveryType:X,dayShift:ee,mapOpenMode:te,inverseOperators:ae,freeDeliveryOperators:ie,operatorsSettings:oe,runOnStart:re,opIcons:se,geoEmptyMessage:ne,freeDlvMinCourier:de,freeDlvMinPVZ:pe,isFitting:ce,fittingDefaultEnabled:le,partialRedemptionEnabled:ue}=(0,r.getSetting)(d+"_data"),ge=(0,i.useCallback)((0,o.debounce)((e=>{if(V(d,"ctpt_ratedata",""),V(d,"ctpt_paychanged","true"),!a.cartNeedsShipping)return;const t=e.flatMap((e=>e.shipping_rates)).find((e=>e.selected));if(t&&Object.prototype.hasOwnProperty.call(t,"method_id")&&t.method_id===d){if(S(wc.wcSettings.getSetting("checkoutData").order_id),t.meta_data.length>0){let e={},a={isSelected:!1,isPVZ:!1,operator:"",operatorLogo:"",tarif:"",pvz:"",dlvTime:""},i="";for(let o in t.meta_data)switch(t.meta_data[o].key){case"ctpt_params":a.isPVZ="pvz"===t.meta_data[o].value.rate_type,e.ctpt_params=t.meta_data[o].value;break;case"variant":a.isSelected=!0,a.operator=t.meta_data[o].value.operator,void 0!==se[a.operator]&&(a.operatorLogo=se[a.operator]),a.tarif=t.meta_data[o].value.rate,e.variant=t.meta_data[o].value;break;case"selected":e.selected=t.meta_data[o].value;break;case"Terminal":i=t.meta_data[o].value.address+"#"+t.meta_data[o].value.code,e.Terminal=t.meta_data[o].value;break;case"dadata":e.dadata=t.meta_data[o].value;break;case"rate_param":e.rate_param=t.meta_data[o].value}a.isPVZ&&(a.pvz=i),l(a),V(d,"ctpt_ratedata",JSON.stringify(e)),V(d,"ctpt_paychanged","false")}w(t.method_id),g(!0)}else g(!1)}),1e3),[]),me=()=>{void 0===window.ctptData&&(window.ctptData=p)};(0,i.useEffect)((()=>{me()}),[]),(0,i.useEffect)((()=>{me(),a.isLoading||a.isLoadingRates||ge(a.shippingRates)}),[a.isLoading,a.isLoadingRates,a.shippingRates,a.shippingAddress]),(0,i.useEffect)((()=>{let e="";"string"==typeof a.shippingAddress.state&&a.shippingAddress.state.length>2&&(e+=a.shippingAddress.state+", "),"string"==typeof a.shippingAddress.city&&a.shippingAddress.city.length<=2||b(e+a.shippingAddress.city)}),[a.shippingAddress.city,a.shippingAddress.state]),(0,i.useEffect)((()=>{const e=document.querySelector("#payment-method .wc-block-components-radio-control"),t=document.querySelectorAll("input[name=radio-control-wc-payment-method-options]");if(null==t||null==e)return;const a=e=>{R(e.target.value)};t.forEach((e=>{e.checked&&R(e.value),e.onchange=a})),document.querySelector("#payment-method .wc-block-components-radio-control").addEventListener("DOMSubtreeModified",(()=>{document.querySelectorAll("input[name=radio-control-wc-payment-method-options]").forEach((e=>{e.checked&&R(e.value),e.onchange=a}))}))}),[document.querySelector("input[name=radio-control-wc-payment-method-options]"),document.querySelector("#payment-method .wc-block-components-radio-control")]),(0,i.useEffect)((()=>{let e=Y.includes(W),t=G.includes(W);V(d,"ctpt_paychanged","true"),D(e||t?{services_filter:"NP,COD",filter_cash:t,filter_card:e}:{services_filter:"",filter_cash:!1,filter_card:!1})}),[W]),(0,i.useEffect)((()=>{let e={...E,...j,location:{address:k},service_path:F,sender_contact_params:{locality_id:M,zip:q,cityFrom:I},isMultiWarehouse:!0,dadata_token:N,only_delivery_type:K,day_shift:ee,cargo:{weight:$,height:Z,width:J,length:U,cargo_comment:B,quantity:1},need_insurance:Q,insured_value:H,startTabMap:te,is_fitting:ce,fitting_default:le,is_partial_redemption:ue,onSelectPvzItem:Se,onSelectCourierItem:ve,onRateResponse:ye,onPopupClose:()=>{"function"==typeof window.CatapultoWidget.destroy&&window.CatapultoWidget.destroy(),delete window.CatapultoWidget,we()}};(null!=A?A:"string"==typeof z)&&(e.ws_api_domain=z),ne.length>2&&(e.geo_data_empty_message=ne),L(e),P(!0)}),[j,k]);const[_e,he]=(0,i.useState)(0),we=()=>{if(he(0),window.CatapultoWidget?("function"==typeof window.CatapultoWidget.destroy&&window.CatapultoWidget.destroy(),delete window.CatapultoWidget,window.CatapultoWidget=new CatapultoWidget2(T)):window.CatapultoWidget=new CatapultoWidget2(T),m||_(!0),void 0===window.ctpt_widgetRunned&&(window.ctpt_widgetRunned=!1),!1===window.ctpt_widgetRunned&&re){let e=!1;for(let t in a.shippingRates[0].shipping_rates)a.shippingRates[0].shipping_rates[t].method_id==d&&a.shippingRates[0].shipping_rates[t].selected&&(e=!0);e&&(window.ctpt_widgetRunned=!0,window.CatapultoWidget.show())}};(0,i.useEffect)((()=>{O&&O&&(_e>0&&clearTimeout(_e),he(setTimeout(we,3e3)))}),[T,u]);const ye=e=>{void 0!==e.results&&e.results.forEach((e=>{void 0===e.price_orig&&(e.price_orig=e.price)}))},fe=e=>{window.CatapultoWidget.hide();const t=window.CatapultoWidget.getData().getVariant();e.dadata=t,e.rate_param=window.CatapultoWidget.getData().RateParams,e.ctpt_params.order_id=wc.wcSettings.getSetting("checkoutData").order_id,e.ctpt_params.isEmpty=!1,e.ctpt_params.insurance=Q,e.ctpt_params.ps=document.querySelector("#payment-method .wc-block-components-radio-control input:checked").value,e.ctpt_params.pr=ue,V(d,"ctpt_ratedata",JSON.stringify(e)),V(d,"ctpt_paychanged","false"),wc.blocksCheckout.extensionCartUpdate({namespace:d,data:e}).then((()=>{let t={isSelected:!0,isPVZ:"pvz"===e.ctpt_params.rate_type,operator:e.variant.operator,operatorLogo:"",tarif:e.variant.rate,pvz:"pvz"===e.ctpt_params.rate_type?e.Terminal.address+"#"+e.Terminal.code:"",dlvTime:""};void 0!==se[t.operator]&&(t.operatorLogo=se[t.operator]),l(t),me(),window.ctptData.isFirstSended||(window.ctptData.isFirstSended=!0,setTimeout((()=>{wc.blocksCheckout.extensionCartUpdate({namespace:d,data:e})}),200))}))},ve=e=>{e&&void 0!==e.variant.id&&(e.ctpt_params={rate_type:"courier",order_id:0},fe(e))},Se=e=>{e&&void 0!==e.Variant&&(e.ctpt_params={rate_type:"pvz",order_id:0},void 0!==e.Variant&&(e.variant=e.Variant,delete e.Variant),fe(e))};return(0,s.jsxs)("div",{className:"wp-block-shipping-catapulto",style:{display:"block"},children:[(0,s.jsx)("input",{type:"hidden",name:"ctpt_hid_cityname"}),u&&(0,s.jsxs)(s.Fragment,{children:[c.isSelected&&(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)("p",{style:{margin:"0"},children:"Способ доставки:"}),(0,s.jsxs)("p",{style:{display:"flex",alignItems:"center",margin:"0"},children:[(0,s.jsx)("b",{style:{paddingRight:"5px"},children:"Оператор: "})," ",c.operator," ",""!=c.operatorLogo&&(0,s.jsx)("img",{style:{width:"60px",marginLeft:"5px"},src:c.operatorLogo})]}),(0,s.jsxs)("p",{style:{margin:"0"},children:[(0,s.jsx)("b",{children:"Тариф: "})," ",c.tarif]}),c.isPVZ&&(0,s.jsxs)("p",{style:{margin:"0"},children:[(0,s.jsx)("b",{children:"ПВЗ: "})," ",c.pvz]})]}),m&&(0,s.jsx)("button",{onClick:e=>{e.preventDefault(),window.CatapultoWidget&&window.CatapultoWidget.show()},style:{height:"40px",width:"220px",background:"#01bd6c",border:"1px solid #01bd6c",borderRadius:"6px",color:"#fff",cursor:"pointer",fontWeight:"700",transition:".5s"},children:"Выбрать способ доставки"})]})]})}})})();
  • catapultodelivery/trunk/catapultodelivery.php

    r3417476 r3444321  
    44 * Plugin URI: https://catapulto.ru
    55 * Description: Catapulto delivery service
    6  * Version: 1.0.0
     6 * Version: 1.0.1
    77 * Requires at least: 5.9
    88 * Text Domain: catapultodelivery
  • catapultodelivery/trunk/languages/ipol_catapultodelivery-ru_RU.po

    r3417476 r3444321  
    131131msgstr "Основные"
    132132
    133 msgid "Terminals"
    134 msgstr "Терминалы"
     133msgid "Terminals and warehouses"
     134msgstr "Терминалы и склады"
    135135
    136136msgid "Dimensions and delivery settings"
     
    245245msgstr "Город отправителя"
    246246
    247 msgid "The city from which you send orders. For example, \"Moscow\" (without quotes)"
    248 msgstr "Город из которого вы отправляете заказы. Например, \"Москва\" (без кавычек)"
     247msgid "The city from which you send orders. For example, «Moscow» (without quotes)"
     248msgstr "Город из которого вы отправляете заказы. Например, «Москва» (без кавычек)"
    249249
    250250msgid "Default Sender ID"
     
    257257msgstr "Уточнить нужное значение для этой настройки можно у менеджера Catapulto"
    258258
    259 msgid "Enable sending by proxy (for \"Business Lines\")"
    260 msgstr "Включить отправку по доверенности (для \"Деловые линии\")"
     259msgid "Enable sending by proxy (for «Business Lines»)"
     260msgstr "Включить отправку по доверенности (для «Деловые линии»)"
    261261
    262262msgid "Full name of contact person"
     
    434434msgstr "Возврат документов"
    435435
     436msgid "Ready to pickup"
     437msgstr "Готов к выдаче"
     438
    436439msgid "First page"
    437440msgstr "Первая страница"
     
    482485msgstr "Вашему отправлению присвоен трек-номер"
    483486
     487msgid "Enable local version of widget"
     488msgstr "Использовать локальную версию виджета"
     489
     490msgid "Do not use this option"
     491msgstr "Не используйте эту опцию"
     492
     493msgid "The dispatch warehouse was not found. You must select a warehouse and a new rate for the shipment"
     494msgstr "Склад отправления не найден, необходимо выбрать склад и новый тариф для отправления"
     495
     496msgid "I cant read the cargo details for this order"
     497msgstr "Не могу прочитать данные грузомест этого заказа"
     498
     499msgid "The weight of the product is not specified"
     500msgstr "Не задан вес у товара"
     501
     502msgid "The height of the product is not set"
     503msgstr "Не задана высота у товара"
     504
     505msgid "The product length is not specified"
     506msgstr "Не задана длина у товара"
     507
     508msgid "The width of the product is not set"
     509msgstr "Не задана ширина у товара"
     510
     511msgid "A mismatch of cargo units was detected. Please reselect the delivery option"
     512msgstr "Обнаружено несовпадение грузомест. Необходимо повторно выбрать вариант доставки"
     513
     514msgid "A discrepancy was detected between the order basket and the package contents. You must delete the packages, recreate them, and select a new shipping calculation"
     515msgstr "Обнаружено несовпадение корзины заказа и состава грузомест. Необходимо удалить грузоместа, составить их заново и выбрать новый расчет доставки"
     516
     517msgid "The Fitting service is included, but the billing was made without this service. A new billing is required"
     518msgstr "Включена услуга \"Примерка\", но расчет сделан без учета этой услуги. Необходимо выполнить новый расчет"
     519
     520msgid "Add warehouse"
     521msgstr "Добавить склад"
     522
     523msgid "Default warehouse"
     524msgstr "Склад по умолчанию"
     525
     526msgid "Warehouse title"
     527msgstr "Название склада"
     528
     529msgid "Settlement"
     530msgstr "Населенный пункт"
     531
     532msgid "Coordinates (latitude, longitude)"
     533msgstr "Координаты (широта, долгота)"
     534
     535msgid "Latitude"
     536msgstr "Широта"
     537
     538msgid "Longitude"
     539msgstr "Долгота"
     540
     541msgid "Not selected"
     542msgstr "Не выбрано"
     543
     544msgid "Senders city ID"
     545msgstr "ID города отправителя"
     546
     547msgid "The city ID from which you ship orders. Please confirm this information with your Catapulto manager"
     548msgstr "ID города из которого вы отправляете заказы. Уточните данную информацию у менеджера Catapulto"
     549
     550msgid "The city postcode from which you ship orders. Please contact your Catapulto manager for this information"
     551msgstr "Индекс города из которого вы отправляете заказы. Уточните данную информацию у менеджера Catapulto"
     552
     553msgid "Warehouse enabled"
     554msgstr "Склад включен"
     555
     556msgid "Delete warehouse"
     557msgstr "Удалить склад"
     558
     559msgid "Delivery operators"
     560msgstr "Операторы доставки"
     561
     562msgid "Free delivery"
     563msgstr "Бесплатная доставка"
     564
     565msgid "Default sending method"
     566msgstr "Способ отправки"
     567
     568msgid "Default terminal code"
     569msgstr "Код терминала по умолчанию"
     570
     571msgid "Fitting available"
     572msgstr "Примерка доступна"
     573
     574msgid "Enable try-on feature. When you select try-on, the widget will only display delivery rates with try-on available"
     575msgstr "Включить возможность примерки. При выборе примерки в виджете отобразятся только тарифы доставки с доступной примеркой"
     576
     577msgid "Fitting enabled by default"
     578msgstr "Включать примерку по умолчанию"
     579
     580msgid "By default, the try-on mode is enabled when the widget is launched"
     581msgstr "По умолчанию режим примерки включен при запуске виджета"
     582
     583msgid "Enable partial buyback by default"
     584msgstr "Включать частичный выкуп по умолчанию"
     585
     586msgid "Enable the partial buyback service by default"
     587msgstr "Включить услугу частичного выкупа по умолчанию"
     588
  • catapultodelivery/trunk/libs/Api/Entity/Request/Part/ShipmentNpData/Item.php

    r3417476 r3444321  
    1010    protected $name;
    1111
    12     /** @var int */
     12    /** @var float */
    1313    protected $quantity;
    1414
     
    6363
    6464    /**
    65      * @return int
    66      */
    67     public function getQuantity(): int
     65     * @return float
     66     */
     67    public function getQuantity(): float
    6868    {
    6969        return $this->quantity;
     
    7171
    7272    /**
    73      * @param int $quantity
     73     * @param float $quantity
    7474     *
    7575     * @return Item
    7676     */
    77     public function setQuantity(int $quantity): Item
     77    public function setQuantity(float $quantity): Item
    7878    {
    7979        $this->quantity = $quantity;
  • catapultodelivery/trunk/libs/Api/Entity/Request/Terminal.php

    r3417476 r3444321  
    5555
    5656    /**
     57     * @var string|null
     58     */
     59    protected $iso;
     60
     61    /**
    5762     * @return int
    5863     */
     
    276281    }
    277282
     283    public function getIso(): ?string
     284    {
     285        return $this->iso;
     286    }
     287
     288    public function setIso(?string $iso): Terminal
     289    {
     290        $this->iso = $iso;
     291        return $this;
     292    }
     293
    278294}
  • catapultodelivery/trunk/libs/Core/Delivery/Cargo.php

    r3417476 r3444321  
    9393        $this->reset();
    9494        while ($item = $this->getNext()) {
    95             $arGabs[] = array($item->getLength(), $item->getWidth(), $item->getHeight(), $item->getQuantity());
     95            $arGabs[] = array($item->getLength(), $item->getWidth(), $item->getHeight(), ceil($item->getQuantity()));
    9696        }
    9797
     
    133133        while($obItem = $this->getNext())
    134134        {
    135             $arGabs[] = array($obItem->getLength(), $obItem->getWidth(), $obItem->getHeight(), $obItem->getQuantity());
     135            $arGabs[] = array($obItem->getLength(), $obItem->getWidth(), $obItem->getHeight(), ceil($obItem->getQuantity()));
    136136        }
    137137
  • catapultodelivery/trunk/libs/Core/Delivery/CargoItem.php

    r3417476 r3444321  
    365365            ->setHeight((int)$data['height'])
    366366            ->setWeight((int)$data['weight'])
    367             ->setQuantity((int)$data['quantity'])
     367            ->setQuantity((float)$data['quantity'])
    368368            ->setPrice(new Money((float)$data['price']['amount'], $data['price']['currency']))
    369369            ->setCost(new Money((float)$data['price']['amount'], $data['price']['currency']))
  • catapultodelivery/trunk/libs/Core/Entity/Money.php

    r3417476 r3444321  
    9191    public function getAmount(): float
    9292    {
    93         return floatval(number_format($this->amount / pow(10, self::$decimal), self::$decimal, '.', ''));
     93        return (float)number_format($this->amount / pow(10, self::$decimal), self::$decimal, '.', '');
    9494    }
    9595
  • catapultodelivery/trunk/libs/Core/Order/Item.php

    r3417476 r3444321  
    5050    protected $price;
    5151    /**
     52     * @var float
     53     */
     54    protected $quantity;
     55    /**
     56     * @var string
     57     */
     58    protected $barcode;
     59    /**
     60     * @var string
     61     */
     62    protected $id;
     63    /**
     64     * @var string
     65     */
     66    protected $articul;
     67    /**
    5268     * @var int
    5369     */
    54     protected $quantity;
    55     /**
    56      * @var string
    57      */
    58     protected $barcode;
    59     /**
    60      * @var string
    61      */
    62     protected $id;
    63     /**
    64      * @var string
    65      */
    66     protected $articul;
    67     /**
    68      * @var int
    69      */
    7070    protected $vatRate;
    7171    /**
     
    265265
    266266    /**
    267      * @return int
     267     * @return floot
    268268     */
    269269    public function getQuantity()
     
    273273
    274274    /**
    275      * @param int $quantity
     275     * @param float $quantity
    276276     * @return $this
    277277     */
  • catapultodelivery/trunk/libs/Core/Order/Payment.php

    r3417476 r3444321  
    6060     */
    6161    protected $isBeznal;
     62   
     63    /**
     64     * @var bool
     65     * 1 for NP, 0 without NP
     66     */
     67    protected $isNp;
     68   
     69    /**
     70     * @var bool
     71     * 1 for COD, 0 without COD
     72     */
     73    protected $isCod;
     74   
     75    /**
     76     * @var bool
     77     * 1 for SMS, 0 without SMS service
     78     */
     79    protected $isSmsAmount;
    6280
    6381    /**
     
    107125        return $this;
    108126    }
    109 
     127   
    110128    /**
    111129     * @return bool
    112130     */
     131    public function getIsNp(): bool
     132    {
     133        return $this->isNp;
     134    }
     135   
     136    /**
     137     * @return bool
     138     */
     139    public function getIsCod(): bool
     140    {
     141        return $this->isCod;
     142    }
     143   
     144    /**
     145     * @return bool
     146     */
     147    public function getIsSmsAmount(): bool
     148    {
     149        return $this->isSmsAmount;
     150    }
     151
     152    /**
     153     * @return bool
     154     */
    113155    public function getIsBeznal(): bool
    114156    {
     
    126168        return $this;
    127169    }
     170   
     171    /**
     172     * @param bool $isNp
     173     * @return $this
     174     */
     175    public function setIsNp(bool $isNp): Payment
     176    {
     177        $this->isNp = $isNp;
     178       
     179        return $this;
     180    }
     181   
     182    /**
     183     * @param bool $isCod
     184     * @return $this
     185     */
     186    public function setIsCod(bool $isCod): Payment
     187    {
     188        $this->isCod = $isCod;
     189       
     190        return $this;
     191    }
     192   
     193    /**
     194     * @param bool $isSmsAmount
     195     * @return $this
     196     */
     197    public function setIsSmsAmount(bool $isSmsAmount): Payment
     198    {
     199        $this->isSmsAmount = $isSmsAmount;
     200       
     201        return $this;
     202    }
    128203
    129204    /**
  • catapultodelivery/trunk/libs/Wordpress/CatapultoPlugin.php

    r3417476 r3444321  
    1111use Ipol\Catapulto\Wordpress\DB\DBTools;
    1212use Ipol\Catapulto\Wordpress\DB\OrdersDB;
     13use Ipol\Catapulto\Wordpress\DB\WarehousesDB;
    1314use Ipol\Catapulto\Wordpress\Frontend\CheckoutBlock;
    1415use Ipol\Catapulto\Wordpress\Rest\RestHandler;
     
    2627    private static $mainPluginDir = '';
    2728    private static $mainPluginUrl = '';
     29    private static $pluginVersion = '';
    2830    private $pluginBaseName;
     31
     32    /** @var string Рассчитывать средние габариты для заказа */
     33    const DEFMODE_O = 'O';
     34    /** @var string Рассчитывать средние габариты для товара */
     35    const DEFMODE_G = 'G';
     36
     37    public const ORDER_META_CARGO = 'ctpt_cargodata';
     38    public const ORDER_META_CARGOCOMMENT = 'ctpt_cargocomment';
    2939
    3040    //OtherConsts
     
    3444    {
    3545        return self::$mainPluginDir;
     46    }
     47
     48    public static function getPluginVersionCode():int
     49    {
     50        $version = self::$pluginVersion;
     51        if (empty($version)) {
     52            return 0;
     53        }
     54        $versionAr = explode('.', $version);
     55        $i = 1;
     56        return array_reduce(array_reverse($versionAr), function ($carry, $item) use (&$i) {
     57            return $carry + (intval($item) * ($i *= 10));
     58        }, 0);
     59    }
     60
     61    public static function isPluginActive():bool
     62    {
     63        if (empty(self::$mainPluginDir)) {
     64            return false;
     65        }
     66        if (empty(self::$mainPluginFile)) {
     67            return false;
     68        }
     69        $basePluginDir = dirname(self::$mainPluginDir) . '/';
     70        $pluginPath = str_replace($basePluginDir, '', self::$mainPluginFile);
     71        return is_plugin_active($pluginPath);
    3672    }
    3773
     
    4177        self::$mainPluginDir = dirname($mainPluginFile);
    4278        self::$mainPluginUrl = plugin_dir_url($mainPluginFile);
     79        self::$pluginVersion = get_file_data($mainPluginFile, ['Version'])[0];
    4380        $this->pluginBaseName = plugin_basename($mainPluginFile);
    4481
     
    4784            ->setMainPluginFile(self::$mainPluginFile)
    4885            ->setMainPluginUrl(self::$mainPluginUrl)
    49             ->setPliginVersion(get_file_data($mainPluginFile, ['Version'])[0]);
     86            ->setPliginVersion(self::$pluginVersion);
    5087
    5188        $this->wpInit();
     
    67104
    68105        add_action('woocommerce_shipping_methods', static function($methods) {
     106            if (self::isPluginActive()) {
     107                CatapultoModuleUpdate::checkUpdate(self::getPluginVersionCode());
     108            }
    69109            $methods[CatapultoPlugin::PLUGIN_ID] = CatapultoShippingMethod::class;
    70110            return $methods;
     
    73113        add_action('wp_head', static function () {
    74114            if (function_exists('wp_enqueue_script_module') && class_exists(FeaturesUtil::class)) {
    75                 wp_enqueue_script_module('catapulto_widget', 'https://widgetcdn.catapulto.ru/assets/js/catapulto-widget/v3/catapulto-widget.js',[]);
     115                $shippingMethod = new CatapultoShippingMethod();
     116                $settings = $shippingMethod->getAllSettings();
     117                $widgetPath = 'https://widgetcdn.catapulto.ru/assets/js/catapulto-widget/v3/catapulto-widget.js';
     118                if (($settings['enLocalWidget'] ?? 'no') === 'yes') $widgetPath = Variables::getMainPluginUrl() . 'assets/js/catapulto-widget.js';
     119                wp_enqueue_script_module('catapulto_widget', $widgetPath,[]);
    76120            }
    77121        });
     
    86130            );
    87131            wp_enqueue_style('ctpt_manage', self::$mainPluginUrl . 'assets/css/admin.css');
    88             wp_enqueue_script_module('widget', 'https://widgetcdn.catapulto.ru/assets/js/catapulto-widget/v3/catapulto-widget.js');
     132            $shippingMethod = new CatapultoShippingMethod();
     133            $settings = $shippingMethod->getAllSettings();
     134            $widgetPath = 'https://widgetcdn.catapulto.ru/assets/js/catapulto-widget/v3/catapulto-widget.js';
     135            if (($settings['enLocalWidget'] ?? 'no') === 'yes') $widgetPath = Variables::getMainPluginUrl() . 'assets/js/catapulto-widget.js';
     136            wp_enqueue_script_module('catapulto_widget', $widgetPath);
    89137        });
    90138
     
    238286            ]);
    239287
     288            //Cargoes
     289            register_rest_route(self::PLUGIN_ID, '/cargocalc', [
     290                'methods'             => \WP_REST_Server::EDITABLE,
     291                'callback'            => [RestHandler::class, 'calcCargoDims'],
     292                'permission_callback' => function() {
     293                    $currentUser = wp_get_current_user();
     294                    return in_array('administrator',$currentUser->roles);
     295                },
     296                'show_in_index'       => true,
     297                'args'                => [],
     298            ]);
     299
     300            register_rest_route(self::PLUGIN_ID, '/cargosave', [
     301                'methods'             => \WP_REST_Server::EDITABLE,
     302                'callback'            => [RestHandler::class, 'cargoSave'],
     303                'permission_callback' => function() {
     304                    $currentUser = wp_get_current_user();
     305                    return in_array('administrator',$currentUser->roles);
     306                },
     307                'show_in_index'       => true,
     308                'args'                => [],
     309            ]);
     310
     311            register_rest_route(self::PLUGIN_ID, '/cargoclear', [
     312                'methods'             => \WP_REST_Server::EDITABLE,
     313                'callback'            => [RestHandler::class, 'cargoClear'],
     314                'permission_callback' => function() {
     315                    $currentUser = wp_get_current_user();
     316                    return in_array('administrator',$currentUser->roles);
     317                },
     318                'show_in_index'       => true,
     319                'args'                => [],
     320            ]);
     321
    240322            // For old version WP
    241323            register_rest_route(self::PLUGIN_ID, '/wpold_ctptsave', [
     
    491573            add_action('wp_footer', static function () {
    492574                if (!is_checkout()) return;
    493                 wp_enqueue_script_module('widget', 'https://widgetcdn.catapulto.ru/assets/js/catapulto-widget/v3/catapulto-widget.js');
     575                $shippingMethod = new CatapultoShippingMethod();
     576                $settings = $shippingMethod->getAllSettings();
     577                $widgetPath = 'https://widgetcdn.catapulto.ru/assets/js/catapulto-widget/v3/catapulto-widget.js';
     578                if (($settings['enLocalWidget'] ?? 'no') === 'yes') $widgetPath = Variables::getMainPluginUrl() . 'assets/js/catapulto-widget.js';
     579                wp_enqueue_script_module('catapulto_widget', $widgetPath);
    494580                wp_enqueue_script('ctpt_widget_handler', self::$mainPluginUrl . 'assets/js/widget_handler.js', ['jquery'], self::ASSETS_VERSION, true);
    495581            });
     
    509595                    $settings = $shippingMethod->getAllSettings();
    510596                    $cargo = Calculator::getCurrentCargoDataByCart();
     597                    $cargoAmount = Calculator::getCartAmount();
    511598
    512599                    $mainController = new MainController(
     
    519606                    );
    520607
    521                     $widgetDeliveryFrom = $settings['widgetDeliveryFrom'];
    522                     $operatorsSettings = [];
    523                     $inverseOperators = [];
    524                     $freeDeliveryOperators = [];
    525608                    $icons = [];
    526609                    $companyIcons = $mainController->getCompanyIcons();
     
    529612                        while ($el = $elements->getNext()) {
    530613                            $icons[$el->getOperatorId()] = $el->getIcon();
    531 
    532                             $operatorSetting = [
    533                                 'operator' => $el->getOperatorId(),
    534                                 'inverse_delivery_type' => false,
    535                                 'free_delivery' => false,
    536                             ];
    537 
    538                             if ($settings['op_type_' . $el->getOperatorId()] != $widgetDeliveryFrom ) {
    539                                 $inverseOperators[] = $el->getOperatorId();
    540                                 $operatorSetting['inverse_delivery_type'] = true;
    541                             }
    542 
    543                             if ($settings['op_free_' . $el->getOperatorId()] === 'yes' ) {
    544                                 $freeDeliveryOperators[] = $el->getOperatorId();
    545                                 $operatorSetting['free_delivery'] = true;
    546                             }
    547                             $operatorsSettings[] = $operatorSetting;
    548614                        }
    549615                    }
     
    554620                    $customWSS = '';
    555621                    if ($settings['isTest'] === 'yes') $customWSS = "ws_api_domain: '{$settings['customWSUrl']}',";
    556 
    557                     $inverseOperatorsStr = "'" . implode("', '", $inverseOperators) . "'";
    558                     if (empty($inverseOperators)) $inverseOperatorsStr = '';
    559 
    560                     $freeDeliveryOperatorsStr = "'" . implode("', '", $freeDeliveryOperators) . "'";
    561                     if (empty($freeDeliveryOperators)) $freeDeliveryOperatorsStr = '';
    562 
    563                     $freeDlvMinCourier = '';
    564                     if (floatval($settings['freeDlvMinCourier']) > 0) $freeDlvMinCourier = 'free_delivery_min_courier: ' . floatval($settings['freeDlvMinCourier']) . ',';
    565                     $freeDlvMinPVZ = '';
    566                     if (floatval($settings['freeDlvMinPVZ']) > 0) $freeDlvMinPVZ = 'free_delivery_min_pvz: ' . floatval($settings['freeDlvMinPVZ']) . ',';
    567 
    568                     // operators_settings
    569                     $operatorSettingsStr = '';
    570                     foreach ($operatorsSettings as $st) {
    571                         if (!empty($operatorSettingsStr)) $operatorSettingsStr .= ',';
    572                         $operatorSettingsStr .= '{"operator":"'.$st['operator'].'", "inverse_delivery_type": '.($st['inverse_delivery_type']?'true':'false').', "free_delivery": '.($st['free_delivery']?'true':'false').'}';
    573                     }
    574622
    575623                    $isCard = false;
     
    590638                    }
    591639
     640                    $localityId = 0;
     641                    $zip = '';
     642                    $cityFrom = '';
     643                    $selectedWH = $shippingMethod->getSenderWarehouse();
     644                    if (is_array($selectedWH)) {
     645                        $localityId = $selectedWH['city_id'];
     646                        $zip = $selectedWH['city_index'];
     647                        $cityFrom = $selectedWH['city_name'];
     648                    }
     649
    592650                    $script = "window.Ctpt_widgetParams = {
    593651                        popup_mode: true,
    594652                        service_path: '/?rest_route=/catapultodelivery/widgethandler',
    595653                        sender_contact_params: {
    596                             locality_id: '{$settings['senderLocalityId']}',
    597                             zip: '{$settings['senderZip']}',
    598                             cityFrom: '{$settings['senderCity']}',
     654                            locality_id: '{$localityId}',
     655                            zip: '{$zip}',
     656                            cityFrom: '{$cityFrom}',
    599657                        },
     658                        isMultiWarehouse: true,
     659                        warehouseId: 0,
    600660                        dadata_token: '{$settings['dadataApikey']}',
    601661                        {$widgetDeliveryTypes}
     
    603663                        delivery_type: '{$settings['widgetDeliveryFrom']}',
    604664                        day_shift: ".intval($settings['termIncrease']).",
    605                         inverse_delivery_type_for_operators: [{$inverseOperatorsStr}],
    606                         free_delivery_operators: [{$freeDeliveryOperatorsStr}],
    607                         operators_settings: [{$operatorSettingsStr}],
    608665                        location: {
    609666                            address: '',
     
    612669                        },
    613670                        cargo: {
    614                             weight: {$cargo['WEI']},
    615                             height: {$cargo['H']},
    616                             length: {$cargo['L']},
    617                             width: {$cargo['W']},
     671                            weight: {$cargo->getWeight()},
     672                            height: {$cargo->getHeight()},
     673                            length: {$cargo->getLength()},
     674                            width: {$cargo->getWidth()},
    618675                            quantity: 1,
    619676                        },
    620677                        need_insurance: ".(($settings['mindEnsurance'] === 'yes')?'true':'false').",
    621                         insured_value: {$cargo['TOTAL']},
     678                        insured_value: {$cargoAmount},
    622679                        {$customWSS}
    623680
     
    627684
    628685                        {$geoEmptyMessage}
    629                         {$freeDlvMinCourier}
    630                         {$freeDlvMinPVZ}
     686
     687                        is_fitting: ".(($settings['isFitting'] === 'yes')?'true':'false').",
     688                        fitting_default: ".(($settings['fittingDefaultEnabled'] === 'yes')?'true':'false').",
     689                        is_partial_redemption: ".(($settings['partialRedemptionEnabled'] === 'yes')?'true':'false').",
    631690
    632691                    };
  • catapultodelivery/trunk/libs/Wordpress/CatapultoShippingMethod.php

    r3417476 r3444321  
    66use Ipol\Catapulto\Wordpress\DB\CartVariantsDB;
    77use Ipol\Catapulto\Wordpress\DB\OperatorsDB;
     8use Ipol\Catapulto\Wordpress\DB\WarehousesDB;
    89use Ipol\Catapulto\Wordpress\Tools\Variables;
    910use Ipol\Catapulto\Wordpress\Tools\VariantStore;
     
    1112class CatapultoShippingMethod extends \WC_Shipping_Method
    1213{
     14    public const CTPT_SENDDLVTYPE_DOOR = 'door';
     15    public const CTPT_SENDDLVTYPE_WAREHOUSE = 'warehouse';
     16
     17    public const CTPT_SERVICE_POD = 'pod_amount'; //Наложенный платеж (NP)
     18    public const CTPT_SERVICE_COD = 'cod_amount'; //Оплата получателем за доставку (COD)
     19    public const CTPT_SERVICE_FITTING = 'fitting_amount'; //Название услуги "Примерка"
     20    public const CTPT_SERVICE_PR = 'partial_redemption_amount'; //Название услуги "Частичный выкуп"
     21    public const CTPT_SERVICE_PR_RETURN = 'partial_redemption_return_amount'; //Название услуги "Частичный возврат товаров"
    1322
    1423    private $operators = [];
     24    private $warehouses = [];
     25
     26    private $isWarehouseTabSelect = false;
    1527
    1628    public function __construct($instance_id = 0)
     
    3143        $operatorsDB = new OperatorsDB();
    3244        $this->operators = $operatorsDB->getAllByColumn('op_enabled','Y');
     45
     46        $warehosesDb = new WarehousesDB();
     47        $this->warehouses = $warehosesDb->getAll();
    3348
    3449        $this->init_settings();
     
    147162                'type' => [],
    148163                'value' => [],
     164                'wh_id' => [],
    149165            ],
    150166            'tr' => [
     167                'class' => [],
    151168                'valign' => [],
    152169            ],
     
    157174            'td' => [
    158175                'class' => [],
     176                'colspan' => [],
    159177            ],
    160178            'label' => [
    161179                'for' => [],
    162180            ],
    163             'fieldset' => [],
     181            'fieldset' => [
     182                'class' => [],
     183            ],
    164184            'legend' => [
    165185                'class' => [],
     
    191211                'type' => [],
    192212                'name' => [],
     213                'placeholder' => [],
    193214            ],
    194215
     
    216237        }
    217238
    218         $operators = '
    219             <tr><th scope="row" class="titledesc"></th><td class="forminp">
    220                 <h3>Операторы доставки, способ отправки, код терминала по умолчанию</h3>
    221                 <div class="ctpt_operators_h">
    222                     <p class="free_dlv">Бесплатная доставка</p>
    223                     <p class="dlv_type">Способ отправки</p>
    224                     <p class="term_code">Код терминала по умолчанию</p>
    225                 </div>
    226             </td></tr>
    227         ';
    228239        $operatorsHidden = '';
    229         foreach ($this->operators as $operator) {
    230             $code = $operator['operator_id'];
    231 
    232             $operators .= '<tr valign="top">
    233                 <th scope="row" class="titledesc">
    234                     <label for="ctpt_op_'.$code.'">'.$operator['operator_display'].'</label>
    235                 </th>
    236                 <td class="forminp ctpt_op_element">
    237                     <fieldset>
    238                         '
    239                         . '<div class="ctpt_check_wr">' . $this->generateCheckboxOnly('op_free_'.$code, $form_fields['op_free_'.$code]) . '</div>'
    240                         . $this->generateSelectOnly('op_type_'.$code, $form_fields['op_type_'.$code])
    241                         . $this->generateTextOnly('op_code_'.$code, $form_fields['op_code_'.$code])
    242                         . '
    243                     </fieldset>
    244                 </td>
    245             </tr>';
    246             $operatorsHidden .=
    247                 $this->generateHiddenCheckbox('op_free_'.$code, $form_fields['op_free_'.$code]) .
    248                 $this->generateHiddenSelect('op_type_'.$code, $form_fields['op_type_'.$code]) .
    249                 $this->generateHiddenInput('op_code_'.$code, $form_fields['op_code_'.$code])
    250             ;
    251         }
    252240
    253241        if (
     
    257245            $this->renderSettingsSection('auth') .
    258246            $statusesFieldsHidden .
    259             $operatorsHidden .
     247            //$operatorsHidden .
    260248            $this->renderHiddenSection('main') .
    261249            $this->renderHiddenSection('terminals') .
     
    270258            '</table>';
    271259
    272         $operators .= '
    273             <tr valign="top">
    274                 <th scope="row" class="titledesc">
    275                     <label for="ctpt_op_btns">' . __('Set up shipping for all courier services', 'catapultodelivery') . ':</label>
    276                 </th>
    277                 <td class="forminp ctpt_op_element">
    278                     <fieldset>
    279                         <button id="ctpt_op_setalldoors" class="components-button is-primary">' . __('From door', 'catapultodelivery') . '</button>
    280                         <button id="ctpt_op_setallwh" class="components-button is-primary">' . __('To warehouse', 'catapultodelivery') . '</button>
    281                     </fieldset>
    282                 </td>
    283             </tr>
    284         ';
    285 
    286260        $nonce = wp_create_nonce('wp_rest');
    287261
    288         $html = '
     262        $html = $this->renderHiddenSection('auth') . '
    289263            <nav class="nav-tab-wrapper woo-nav-tab-wrapper" data-tabs-content-level="2">
    290                 <a href="#" class="nav-tab ctpt-tab nav-tab-active" data-tab-content-id="ctpt_settings_main">' . __('Main', 'catapultodelivery') . '</a>
    291                 <a href="#" class="nav-tab ctpt-tab" data-tab-content-id="ctpt_settings_terminals">' . __('Terminals', 'catapultodelivery') . '</a>
     264                <a href="#" class="nav-tab ctpt-tab' . (!$this->isWarehouseTabSelect ? ' nav-tab-active' : '') . '" data-tab-content-id="ctpt_settings_main">' . __('Main', 'catapultodelivery') . '</a>
     265                <a href="#" class="nav-tab ctpt-tab' . ($this->isWarehouseTabSelect ? ' nav-tab-active' : '') . '" data-tab-content-id="ctpt_settings_terminals">' . __('Terminals and warehouses', 'catapultodelivery') . '</a>
    292266                <a href="#" class="nav-tab ctpt-tab" data-tab-content-id="ctpt_settings_gabs">' . __('Dimensions and delivery settings', 'catapultodelivery') . '</a>
    293267                <a href="#" class="nav-tab ctpt-tab" data-tab-content-id="ctpt_settings_statuses">' . __('Synchronization of statuses', 'catapultodelivery') . '</a>
     
    297271            </nav>
    298272            <div class="tab-wrapper">
    299                 <div class="ctpt-tab-content-2" id="ctpt_settings_main">
     273                <input type="hidden" name="is_new_wh" value="N" />
     274                <input type="hidden" name="is_wh_del" value="N" />
     275                <div class="ctpt-tab-content-2' . ($this->isWarehouseTabSelect ? ' ctpt_tab_hidden' : '') . '" id="ctpt_settings_main">
    300276                    <div class="ctpt_tbl">
    301277                        <p style="font-size: 20px"><b>' . __('Api key', 'catapultodelivery') . ': </b>' . \mb_substr($this->settings['apikey'], 0, 30) . '...</p>
     
    310286                    </table>
    311287                </div>
    312                 <div class="ctpt-tab-content-2" id="ctpt_settings_terminals" style="display:none;">
     288                <div class="ctpt-tab-content-2' . ($this->isWarehouseTabSelect ? '' : ' ctpt_tab_hidden') . '" id="ctpt_settings_terminals">
    313289                    <h3>' . __('Default sending method and sending terminals', 'catapultodelivery') . '</h3>
    314290                    <table class="form-table">
    315                     '.$this->renderSettingsSection('terminals') . $operators . '
     291                    ' . $this->renderWarehousesSettings() . '
    316292                    </table>
    317293                </div>
    318                 <div class="ctpt-tab-content-2" id="ctpt_settings_gabs" style="display:none;">
     294                <div class="ctpt-tab-content-2 ctpt_tab_hidden" id="ctpt_settings_gabs">
    319295                    <h3>' . __('Default dimensions', 'catapultodelivery') . '</h3>
    320296                    <table class="form-table">'.$this->renderSettingsSection('gabs').'</table>
     
    323299                    <table class="form-table">'.$this->renderSettingsSection('dlvsettings').'</table>
    324300                </div>
    325                 <div class="ctpt-tab-content-2" id="ctpt_settings_statuses" style="display:none;">
     301                <div class="ctpt-tab-content-2 ctpt_tab_hidden" id="ctpt_settings_statuses">
    326302                    <h3>' . __('Synchronization of statuses', 'catapultodelivery') . '</h3>
    327303                    <table class="form-table">'
     
    330306                    .'</table>
    331307                </div>
    332                 <div class="ctpt-tab-content-2" id="ctpt_settings_widget" style="display:none;">
     308                <div class="ctpt-tab-content-2 ctpt_tab_hidden" id="ctpt_settings_widget">
    333309                    <h3>' . __('Widget settings', 'catapultodelivery') . '</h3>
    334310                    <table class="form-table">'.$this->renderSettingsSection('widget').'</table>
    335311                </div>
    336                 <div class="ctpt-tab-content-2" id="ctpt_settings_paysystems" style="display:none;">
     312                <div class="ctpt-tab-content-2 ctpt_tab_hidden" id="ctpt_settings_paysystems">
    337313                    <h3>' . __('Payment system compliance settings', 'catapultodelivery') . '</h3>
    338314                    <h4>' . __('Explanation of payment systems', 'catapultodelivery') . '</h4>
     
    346322                    . '</table>
    347323                </div>
    348                 <div class="ctpt-tab-content-2" id="ctpt_settings_service" style="display:none;">
     324                <div class="ctpt-tab-content-2 ctpt_tab_hidden" id="ctpt_settings_service">
    349325                    <h3>' . __('Service properties', 'catapultodelivery') . '</h3>
    350326                    <table class="form-table">'.$this->renderSettingsSection('service').'</table>
     
    354330
    355331        return $html;
     332    }
     333
     334    private function renderWarehousesSettings():string
     335    {
     336        $out = '<tr><td class="forminp ctpt_wh_actions" colspan="2">
     337                    <fieldset>
     338                        <p>' . __('Default warehouse', 'catapultodelivery') . ':</p>
     339                        ' . $this->generateSelectOnly('wh_default_selected', $this->form_fields['wh_default_selected']) . '
     340                        <button id="ctpt_new_wh" class="components-button is-primary">' . __('Add warehouse', 'catapultodelivery') . '</button>
     341                    </fieldset>
     342                </td></tr>';
     343
     344        foreach ($this->warehouses as $wh) {
     345            $out .= $this->renderWarehouseBlock($wh);
     346        }
     347
     348        return $out;
     349    }
     350
     351    private function renderWarehouseBlock(array $warehouseData)
     352    {
     353        $pf = '_chwh_' . $warehouseData['id'];
     354        $operatorsData = json_decode($warehouseData['operators'], true);
     355        if (!$operatorsData) $operatorsData = [];
     356
     357        $operators = '';
     358        foreach ($this->operators as $operator) {
     359            $code = $operator['operator_id'];
     360
     361            $opdata = $operatorsData[$code] ?? [
     362                'f' => false, //isfree
     363                't' => self::CTPT_SENDDLVTYPE_DOOR,//from door/warehouse
     364                'c' => '', //pvz_code
     365            ];
     366
     367            $operators .= '
     368                <fieldset>
     369                    <div class="ctpt_bl_d4">
     370                        <p>'.$operator['operator_display'].'</p>
     371                    </div>
     372                    <div class="ctpt_bl_d4">
     373                        '.$this->generateCheckboxOnly('op_free_' . $code . $pf, [
     374                            'title' => '',
     375                            'description' => '',
     376                            'desc_tip' => false,
     377                            'type' => 'checkbox',
     378                            'default' => $opdata['f'] ? '1' : '0',
     379                        ], $opdata['f']).'
     380                    </div>
     381                    <div class="ctpt_bl_d4 ctpt_wh_select_dlv_type">
     382                        '.$this->generateSelectOnly('op_type_' . $code . $pf, [
     383                            'title'   => '',
     384                            'type'    => 'select',
     385                            'default' => $opdata['t'],
     386                            'description' => '',
     387                            'desc_tip'    => false,
     388                            'options'=> [
     389                                self::CTPT_SENDDLVTYPE_DOOR => __('From door', 'catapultodelivery'),
     390                                self::CTPT_SENDDLVTYPE_WAREHOUSE => __('To warehouse', 'catapultodelivery'),
     391                            ]
     392                        ], $opdata['t']).'
     393                    </div>
     394                    <div class="ctpt_bl_d4 ctpt_wh_select_dlv_code hid">
     395                        '.$this->generateTextOnly('op_code_' . $code . $pf, [
     396                            'title' => '',
     397                            'description' => '',
     398                            'desc_tip' => false,
     399                            'type' => 'text',
     400                            'default' => $opdata['c'],
     401                        ]).'
     402                    </div>
     403                </fieldset>
     404            ';
     405        }
     406
     407        $out = '
     408            <tr class="ctpt_warehouse">
     409                <input type="hidden" name="id' . $pf . '" value="' . $warehouseData['id'] . '" />
     410                <td class="ctpt_sender">
     411                    <fieldset class="wh_name_fs">
     412                    <label>' . __('Warehouse title', 'catapultodelivery') . ':</label>
     413                    ' . $this->generateTextOnly('name' . $pf, [
     414                'title' => __('Warehouse title', 'catapultodelivery'),
     415                'description' => '',
     416                'desc_tip' => false,
     417                'type' => 'text',
     418                'default' => $warehouseData['name'],
     419            ]) . '</fieldset>
     420
     421                    <fieldset class="wh_name_fs">
     422                    <label>' . __('Settlement', 'catapultodelivery') . ':</label>
     423                    ' . $this->generateTextOnly('cityname' . $pf, [
     424                'title' => __('Settlement', 'catapultodelivery'),
     425                'description' => '',
     426                'desc_tip' => false,
     427                'type' => 'text',
     428                'default' => $warehouseData['city_name'],
     429            ]) . '</fieldset>
     430
     431                    <fieldset  class="wh_coords">
     432                        <label>' . __('Coordinates (latitude, longitude)', 'catapultodelivery') . ':</label>
     433                        <fieldset>
     434                        ' . $this->generateTextOnly('lat' . $pf, [
     435                'title' => __('Latitude', 'catapultodelivery'),
     436                'description' => '',
     437                'desc_tip' => false,
     438                'type' => 'text',
     439                'default' => $warehouseData['lat'],
     440            ]) . '
     441                        ' . $this->generateTextOnly('lon' . $pf, [
     442                'title' => __('Longitude', 'catapultodelivery'),
     443                'description' => '',
     444                'desc_tip' => false,
     445                'type' => 'text',
     446                'default' => $warehouseData['lon'],
     447            ]) . '
     448                        </fieldset>
     449                    </fieldset>
     450
     451                    <fieldset class="wh_digits wh_cityid">
     452                    <label>' . __('Senders city ID', 'catapultodelivery') . ':</label>
     453                    ' . $this->generateTextOnly('city_id' . $pf, [
     454                'title' => __('Senders city ID', 'catapultodelivery'),
     455                'description' => __('The city ID from which you ship orders. Please confirm this information with your Catapulto manager', 'catapultodelivery'),
     456                'desc_tip' => true,
     457                'type' => 'text',
     458                'default' => intval($warehouseData['city_id']) > 0 ? $warehouseData['city_id'] : '',
     459            ]) . '
     460                    </fieldset>
     461
     462                    <fieldset class="wh_digits wh_cityzip">
     463                    <label>' . __('Sender zip', 'catapultodelivery') . ':</label>
     464                    ' . $this->generateTextOnly('city_index' . $pf, [
     465                'title' => __('Sender zip', 'catapultodelivery'),
     466                'description' => __('The city postcode from which you ship orders. Please contact your Catapulto manager for this information', 'catapultodelivery'),
     467                'desc_tip' => true,
     468                'type' => 'text',
     469                'default' => intval($warehouseData['city_index']) > 0 ? $warehouseData['city_index'] : '',
     470            ]) . '
     471                    </fieldset>
     472
     473                    <fieldset class="wh_digits wh_senderid">
     474                    <label>' . __('Default Sender ID', 'catapultodelivery') . ':</label>
     475                    ' . $this->generateTextOnly('contact_id' . $pf, [
     476                'title' => __('Default Sender ID', 'catapultodelivery'),
     477                'description' => __('The contact ID from the address book in your Catapulto account, which will be selected by the sender in the module', 'catapultodelivery'),
     478                'desc_tip' => true,
     479                'type' => 'text',
     480                'default' => intval($warehouseData['contact_id']) > 0 ? $warehouseData['contact_id'] : '',
     481            ]) . '
     482                    </fieldset>
     483
     484                    <fieldset class="wh_amount">
     485                    <label>' . __('Free courier delivery from, RUB', 'catapultodelivery') . ':</label>
     486                    ' . $this->generateTextOnly('free_courier_from' . $pf, [
     487                'title' => __('Free courier delivery from, RUB', 'catapultodelivery'),
     488                'description' => '',
     489                'desc_tip' => true,
     490                'type' => 'text',
     491                'default' => $warehouseData['free_courier_from'],
     492            ]) . '
     493                    </fieldset>
     494
     495                    <fieldset class="wh_amount">
     496                    <label>' . __('Free delivery to pick-up points from, RUB', 'catapultodelivery') . ':</label>
     497                    ' . $this->generateTextOnly('free_pickup_from' . $pf, [
     498                'title' => __('Free delivery to pick-up points from, RUB', 'catapultodelivery'),
     499                'description' => '',
     500                'desc_tip' => true,
     501                'type' => 'text',
     502                'default' => $warehouseData['free_pickup_from'],
     503            ]) . '
     504                    </fieldset>
     505
     506                    <fieldset class="wh_poa_enable">
     507                    <label>' . __('Enable sending by proxy (for «Business Lines»)', 'catapultodelivery') . ':</label>
     508                    ' . $this->generateCheckboxOnly('poa_enabled' . $pf, [
     509                'title' => __('Enable sending by proxy (for «Business Lines»)', 'catapultodelivery'),
     510                'description' => '',
     511                'desc_tip' => false,
     512                'type' => 'checkbox',
     513                'default' => 'no',
     514            ], $warehouseData['poa_enabled'] === 'Y') . '
     515                    </fieldset>
     516
     517                    <fieldset class="wh_poa_fio">
     518                    <label>' . __('Full name of contact person', 'catapultodelivery') . ':</label>
     519                    ' . $this->generateTextOnly('poa_fio' . $pf, [
     520                'title' => __('Full name of contact person', 'catapultodelivery'),
     521                'description' => '',
     522                'desc_tip' => true,
     523                'type' => 'text',
     524                'default' => $warehouseData['poa_from_fio'],
     525            ]) . '
     526                    </fieldset>
     527
     528                    <fieldset class="wh_poa_p_ser">
     529                    <label>' . __('Passport series (4 digits)', 'catapultodelivery') . ':</label>
     530                    ' . $this->generateTextOnly('poa_series' . $pf, [
     531                'title' => __('Passport series (4 digits)', 'catapultodelivery'),
     532                'description' => '',
     533                'desc_tip' => true,
     534                'type' => 'text',
     535                'default' => $warehouseData['poa_from_p_series'],
     536            ]) . '
     537                    </fieldset>
     538
     539                    <fieldset class="wh_poa_p_num">
     540                    <label>' . __('Passport number (6 digits)', 'catapultodelivery') . ':</label>
     541                    ' . $this->generateTextOnly('poa_number' . $pf, [
     542                'title' => __('Passport number (6 digits)', 'catapultodelivery'),
     543                'description' => '',
     544                'desc_tip' => true,
     545                'type' => 'text',
     546                'default' => $warehouseData['poa_from_p_number'],
     547            ]) . '
     548                    </fieldset>
     549
     550                    <fieldset class="wh_poa_p_date">
     551                    <label>' . __('Date of issue (dd.mm.yyyy)', 'catapultodelivery') . ':</label>
     552                    ' . $this->generateTextOnly('poa_date' . $pf, [
     553                'title' => __('Date of issue (dd.mm.yyyy)', 'catapultodelivery'),
     554                'description' => '',
     555                'desc_tip' => true,
     556                'type' => 'text',
     557                'default' => $warehouseData['poa_from_p_date'],
     558            ]) . '
     559                    </fieldset>
     560
     561                    <fieldset class="wh_poa_p_mail">
     562                    <label>' . __('Email for sending power of attorney (optional)', 'catapultodelivery') . ':</label>
     563                    ' . $this->generateTextOnly('poa_email' . $pf, [
     564                'title' => __('Email for sending power of attorney (optional)', 'catapultodelivery'),
     565                'description' => '',
     566                'desc_tip' => true,
     567                'type' => 'text',
     568                'default' => $warehouseData['poa_from_email'],
     569            ]) . '
     570                    </fieldset>
     571
     572                </td>
     573                <td class="ctpt_operators">
     574                    <fieldset class="ctpt_wh_active">
     575                        <label>' . __('Warehouse enabled', 'catapultodelivery') . '</label>
     576                        ' . $this->generateCheckboxOnly('enabled' . $pf, [
     577                'title' => '',
     578                'description' => '',
     579                'desc_tip' => false,
     580                'type' => 'checkbox',
     581                'default' => 'no',
     582            ], $warehouseData['active'] === 'Y') . '
     583
     584                        <div class="ctpt_wh_delete_wr">
     585                            <button id="ctpt_wh_delete" wh_id="'.$warehouseData['id'].'" class="components-button is-primary">' . __('Delete warehouse', 'catapultodelivery') . '</button>
     586                        </div>
     587                    </fieldset>
     588
     589                    <fieldset>
     590                        <label>' . __('Default method for sending shipments', 'catapultodelivery') . ':</label>
     591                        ' . $this->generateSelectOnly('dlv_default_from' . $pf, [
     592                'title'   => '',
     593                'type'    => 'select',
     594                'default' => $warehouseData['delivery_from'],
     595                'description' => '',
     596                'desc_tip'    => false,
     597                'options'=> [
     598                    self::CTPT_SENDDLVTYPE_DOOR => __('From door', 'catapultodelivery'),
     599                    self::CTPT_SENDDLVTYPE_WAREHOUSE => __('To warehouse', 'catapultodelivery'),
     600                ]
     601            ], $warehouseData['delivery_from']) . '
     602                    </fieldset>
     603
     604                    <fieldset>
     605                        <div class="ctpt_bl_d4">
     606                            <p><b>' . __('Delivery operators', 'catapultodelivery') . '</b></p>
     607                        </div>
     608                        <div class="ctpt_bl_d4">
     609                            <p><b>' . __('Free delivery', 'catapultodelivery') . '</b></p>
     610                        </div>
     611                        <div class="ctpt_bl_d4">
     612                            <p><b>' . __('Default sending method', 'catapultodelivery') . '</b></p>
     613                        </div>
     614                        <div class="ctpt_bl_d4">
     615                            <p><b>' . __('Default terminal code', 'catapultodelivery') . '</b></p>
     616                        </div>
     617                    </fieldset>
     618
     619                    '.$operators.'
     620                </td>
     621            </tr>
     622            <tr class="ctpt_warehouse_after"><td colspan="2"></td></tr>
     623        ';
     624
     625        return $out;
    356626    }
    357627
     
    501771
    502772        return '
    503             <textarea rows="3" cols="20" type="'.$inputType.'" name="'.$idEl.'" id="'.$idEl.'" style="display:none !important;">'.$currentValue.'</textarea>
     773            <textarea rows="3" cols="20" type="'.$inputType.'" name="'.$idEl.'" id="'.$idEl.'" class="ctpt_inputhidden">'.$currentValue.'</textarea>
    504774        ';
    505775    }
     
    541811    {
    542812        $field_key = $this->get_field_key( $key );
     813        $savedValue = $this->get_option( $key );
    543814        $defaults  = [
    544815            'title'             => '',
     
    551822            'description'       => '',
    552823            'custom_attributes' => [],
     824            'value'             => empty($savedValue) ? $data['default'] : $savedValue,
    553825        ];
    554826
    555827        $data = wp_parse_args( $data, $defaults );
    556828
    557         return '<input class="input-text regular-input '.esc_attr( $data['class'] ).'" type="'.esc_attr( $data['type'] ).'" name="'.esc_attr( $field_key ).'" id="'.esc_attr( $field_key ).'" style="'.esc_attr( $data['css'] ).'" value="'.esc_attr( $this->get_option( $key ) ).'" placeholder="'.esc_attr( $data['placeholder'] ).'" '.disabled( $data['disabled'], true ).' '.$this->get_custom_attribute_html( $data ).' />';
     829        return '<input class="input-text regular-input '.esc_attr( $data['class'] ).'" type="'.esc_attr( $data['type'] ).'" name="'.esc_attr( $field_key ).'" id="'.esc_attr( $field_key ).'" style="'.esc_attr( $data['css'] ).'" value="'.esc_attr( $data['value'] ).'" placeholder="'.esc_attr( $data['placeholder'] ).'" '.disabled( $data['disabled'], true ).' '.$this->get_custom_attribute_html( $data ).' />';
    558830    }
    559831
     
    592864        </tr>';
    593865    }
    594     private function generateCheckboxOnly( $key, $data ) {
     866    private function generateCheckboxOnly( $key, $data, $isForseChecked = false ) {
    595867        $field_key = $this->get_field_key( $key );
    596868        $defaults  = [
     
    611883            $data['label'] = $data['title'];
    612884        }
    613 
    614         return '<input class="'.esc_attr( $data['class'] ).'" type="checkbox" name="'.esc_attr( $field_key ).'" id="'.esc_attr( $field_key ).'" value="1" '.checked( $this->get_option( $key ), 'yes', false ).' '.$this->get_custom_attribute_html( $data ).' />';
     885        $value = $this->get_option( $key );
     886        if ($isForseChecked) $value = 'yes';
     887
     888        return '<input class="'.esc_attr( $data['class'] ).'" type="checkbox" name="'.esc_attr( $field_key ).'" id="'.esc_attr( $field_key ).'" value="1" '.checked( $value, 'yes', false ).' '.$this->get_custom_attribute_html( $data ).' />';
    615889    }
    616890
     
    659933        </tr>';
    660934    }
    661     private function generateSelectOnly( $key, $data ) {
     935    private function generateSelectOnly( $key, $data, $forseValue = '' ) {
    662936        $field_key = $this->get_field_key( $key );
    663937        $defaults  = [
     
    676950        $data  = wp_parse_args( $data, $defaults );
    677951        $value = $this->get_option( $key );
     952        if (!empty($forseValue)) $value = $forseValue;
    678953
    679954        $optionsHtml = '';
     
    8101085                'title'   => '',
    8111086                'type'    => 'select',
    812                 'default' => 'door',
     1087                'default' => self::CTPT_SENDDLVTYPE_DOOR,
    8131088                'description' => '',
    8141089                'desc_tip'    => false,
    8151090                'options'=> [
    816                     'door' => __('From door', 'catapultodelivery'),
    817                     'warehouse' => __('To warehouse', 'catapultodelivery'),
     1091                    self::CTPT_SENDDLVTYPE_DOOR => __('From door', 'catapultodelivery'),
     1092                    self::CTPT_SENDDLVTYPE_WAREHOUSE => __('To warehouse', 'catapultodelivery'),
    8181093                ]
    8191094            ];
     
    8331108            ];
    8341109        }
     1110
     1111        //warehouses....
     1112        $defaultWHValue = [
     1113            '0' => __('Not selected', 'catapultodelivery'),
     1114        ];
     1115        foreach ($this->warehouses as $wh) {
     1116            if ($wh['active'] != 'Y') continue;
     1117            $defaultWHValue[$wh['id']] = $wh['name'] . ' ('.$wh['id'].')';
     1118        }
     1119        $this->form_fields['wh_default_selected'] = [
     1120            'title'   => '',
     1121            'type'    => 'select',
     1122            'default' => '0',
     1123            'description' => '',
     1124            'desc_tip'    => false,
     1125            'options'=> $defaultWHValue
     1126        ];
     1127
    8351128    }
    8361129
    8371130    public function validate_text_field($key, $value)
    8381131    {
     1132        static $whNewSaved;
     1133
    8391134        $postData = $this->get_post_data();
    8401135        $isAuthMode = isset($postData['ctptIsAuth']) && ($postData['ctptIsAuth'] === 'Y');
     1136
     1137        // save warehouses
     1138        $warehosesDb = new WarehousesDB();
     1139        //new warehouse
     1140        if ($postData['is_new_wh'] == 'Y' && $whNewSaved === null) {
     1141            $this->isWarehouseTabSelect = true;
     1142            $isAddPermitted = true;
     1143            foreach ($this->warehouses as $wh) {
     1144                if (empty($wh['name'])) $isAddPermitted = false;
     1145            }
     1146
     1147            if ($isAddPermitted) {
     1148                $newWHData = [
     1149                    'city_id' => 0,
     1150                    'city_index' => 0,
     1151                    'contact_id' => 0,
     1152                    'name' => '',
     1153                    'city_name' => '',
     1154                    'delivery_from' => '',
     1155                    'free_courier_from' => '',
     1156                    'free_pickup_from' => '',
     1157                    'poa_enabled' => 'N',
     1158                    'poa_from_fio' => '',
     1159                    'poa_from_p_series' => '',
     1160                    'poa_from_p_number' => '',
     1161                    'poa_from_p_date' => '',
     1162                    'poa_from_email' => '',
     1163                    'lat' => '',
     1164                    'lon' => '',
     1165                    'operators' => '',
     1166                    'active' => 'N',
     1167                ];
     1168                $warehosesDb->saveOrUpdate($newWHData);
     1169                $newWHData['id'] = $warehosesDb->getLastRecordId();
     1170                $this->warehouses[] = $newWHData;
     1171            }
     1172
     1173            $whNewSaved = true;
     1174        }
     1175        if ($postData['is_wh_del'] != 'N' && $whNewSaved === null) {
     1176            $this->isWarehouseTabSelect = true;
     1177            $delWHId = intval($postData['is_wh_del']);
     1178            if ($delWHId > 0) {
     1179                $warehosesDb->deleteById($delWHId);
     1180                foreach ($this->warehouses as $whKey => $wh) {
     1181                    if (intval($wh['id']) == $delWHId) {
     1182                        unset($this->warehouses[$whKey]);
     1183                        break;
     1184                    }
     1185                }
     1186            }
     1187            $whNewSaved = true;
     1188        }
     1189
     1190        //save current warehouses...
     1191        if ($whNewSaved === null) {
     1192            foreach ($this->warehouses as $whKey => $currentWH) {
     1193                $currentId = intval($currentWH['id']);
     1194
     1195                $currentWH['city_id'] = intval($postData['woocommerce_catapultodelivery_city_id_chwh_' . $currentId]);
     1196                $currentWH['city_index'] = intval($postData['woocommerce_catapultodelivery_city_index_chwh_' . $currentId]);
     1197                $currentWH['contact_id'] = intval($postData['woocommerce_catapultodelivery_contact_id_chwh_' . $currentId]);
     1198                $currentWH['city_name'] = $postData['woocommerce_catapultodelivery_cityname_chwh_' . $currentId];
     1199                $currentWH['name'] = $postData['woocommerce_catapultodelivery_name_chwh_' . $currentId];
     1200                $currentWH['delivery_from'] = $postData['woocommerce_catapultodelivery_dlv_default_from_chwh_' . $currentId];
     1201                $currentWH['free_courier_from'] = $postData['woocommerce_catapultodelivery_free_courier_from_chwh_' . $currentId];
     1202                $currentWH['free_pickup_from'] = $postData['woocommerce_catapultodelivery_free_pickup_from_chwh_' . $currentId];
     1203                $currentWH['poa_enabled'] = ( ($postData['woocommerce_catapultodelivery_poa_enabled_chwh_' . $currentId] ?? '0') === '1' ) ? 'Y' : 'N';
     1204                $currentWH['poa_from_fio'] = $postData['woocommerce_catapultodelivery_poa_fio_chwh_' . $currentId];
     1205                $currentWH['poa_from_p_series'] = $postData['woocommerce_catapultodelivery_poa_series_chwh_' . $currentId];
     1206                $currentWH['poa_from_p_number'] = $postData['woocommerce_catapultodelivery_poa_number_chwh_' . $currentId];
     1207                $currentWH['poa_from_p_date'] = $postData['woocommerce_catapultodelivery_poa_date_chwh_' . $currentId];
     1208                $currentWH['poa_from_email'] = $postData['woocommerce_catapultodelivery_poa_email_chwh_' . $currentId];
     1209                $currentWH['lat'] = $postData['woocommerce_catapultodelivery_lat_chwh_' . $currentId];
     1210                $currentWH['lon'] = $postData['woocommerce_catapultodelivery_lon_chwh_' . $currentId];
     1211                $currentWH['active'] = ( ($postData['woocommerce_catapultodelivery_enabled_chwh_' . $currentId] ?? '0') === '1' ) ? 'Y' : 'N';
     1212
     1213                // Operators...
     1214                $whOpData = [];
     1215                foreach ($this->operators as $operator) {
     1216                    $code = $operator['operator_id'];
     1217                    $whOpData[$code] = [
     1218                        'f' => ($postData["woocommerce_catapultodelivery_op_free_{$code}_chwh_{$currentId}"] ?? '0') === '1',
     1219                        't' => $postData["woocommerce_catapultodelivery_op_type_{$code}_chwh_{$currentId}"],
     1220                        'c' => ($postData["woocommerce_catapultodelivery_op_type_{$code}_chwh_{$currentId}"] === self::CTPT_SENDDLVTYPE_WAREHOUSE) ? $postData["woocommerce_catapultodelivery_op_code_{$code}_chwh_{$currentId}"] : '',
     1221                    ];
     1222                }
     1223                $currentWH['operators'] = json_encode($whOpData);
     1224                // /Operators...
     1225
     1226                //save to db
     1227                $warehosesDb->saveOrUpdate($currentWH, 'id');
     1228
     1229                $this->warehouses[$whKey] = $currentWH;
     1230                $this->form_fields['wh_default_selected']['options'][$currentId] = $currentWH['name'] . ' ('.$currentId.')';
     1231            }
     1232            $whNewSaved = true;
     1233        }
    8411234
    8421235        $value = parent::validate_text_field($key, $value);
     
    9751368                    'type' => 'title',
    9761369                ],
    977                 'senderLocalityId' => [
    978                     'title' => __('Sender city ID', 'catapultodelivery'),
    979                     'description' => __('ID of the city from which you send orders. Check this information with the Catapulto manager', 'catapultodelivery') . '.',
    980                     'desc_tip' => true,
    981                     'type' => 'text',
    982                     'default' => '',
    983                 ],
    984                 'senderZip' => [
    985                     'title' => __('Sender zip', 'catapultodelivery'),
    986                     'description' => __('The city index from which you send orders. Check this information with the Catapulto manager', 'catapultodelivery') . '.',
    987                     'desc_tip' => true,
    988                     'type' => 'text',
    989                     'default' => '',
    990                 ],
    991                 'senderCity' => [
    992                     'title' => __('Sender`s city', 'catapultodelivery'),
    993                     'description' => __("The city from which you send orders. For example, \"Moscow\" (without quotes)", 'catapultodelivery'),
    994                     'desc_tip' => true,
    995                     'type' => 'text',
    996                     'default' => '',
    997                 ],
    998                 'senderId' => [
    999                     'title' => __('Default Sender ID', 'catapultodelivery'),
    1000                     'description' => __('The contact ID from the address book in your Catapulto account, which will be selected by the sender in the module', 'catapultodelivery') .  '.<br/> ' . __('You can check the required value for this setting with the Catapulto manager', 'catapultodelivery'),
    1001                     'desc_tip' => true,
    1002                     'type' => 'text',
    1003                     'default' => '',
    1004                 ],
    1005                 'poaEnabled' => [
    1006                     'title'   => __("Enable sending by proxy (for \"Business Lines\")", 'catapultodelivery'),
    1007                     'type'    => 'checkbox',
    1008                     'default' => ''
    1009                 ],
    1010                 'poaFromName' => [
    1011                     'title' => __('Full name of contact person', 'catapultodelivery'),
    1012                     'description' => '',
    1013                     'desc_tip' => false,
    1014                     'type' => 'text',
    1015                     'default' => '',
    1016                 ],
    1017                 'poaFromPassportSeries' => [
    1018                     'title' => __('Passport series (4 digits)', 'catapultodelivery'),
    1019                     'description' => '',
    1020                     'desc_tip' => false,
    1021                     'type' => 'text',
    1022                     'default' => '',
    1023                 ],
    1024                 'poaFromPassportNumber' => [
    1025                     'title' => __('Passport number (6 digits)', 'catapultodelivery'),
    1026                     'description' => '',
    1027                     'desc_tip' => false,
    1028                     'type' => 'text',
    1029                     'default' => '',
    1030                 ],
    1031                 'poaFromPassportDate' => [
    1032                     'title' => __('Date of issue (dd.mm.yyyy)', 'catapultodelivery'),
    1033                     'description' => '',
    1034                     'desc_tip' => false,
    1035                     'type' => 'text',
    1036                     'default' => '',
    1037                 ],
    1038                 'poaSendReceiverEmail' => [
    1039                     'title' => __('Email for sending power of attorney (optional)', 'catapultodelivery'),
    1040                     'description' => '',
    1041                     'desc_tip' => false,
    1042                     'type' => 'text',
    1043                     'default' => '',
    1044                 ],
    10451370            ],
    10461371            'terminals'=>[
    1047                 'widgetDeliveryFrom' => [
    1048                     'title'   => __('Default method for sending shipments', 'catapultodelivery'),
    1049                     'type'    => 'select',
    1050                     'default' => 'door',
    1051                     'description' => '',
    1052                     'desc_tip'    => false,
    1053                     'options'=> [
    1054                         'door' => __('From door', 'catapultodelivery'),
    1055                         'warehouse' => __('From warehouse', 'catapultodelivery'),
    1056                     ]
    1057                 ],
    1058                 //Terminals....
    1059                 'freeDlvMinCourier' => [
    1060                     'title' => __('Free courier delivery from, RUB', 'catapultodelivery') . '.',
    1061                     'description' => '',
    1062                     'desc_tip' => false,
    1063                     'type' => 'text',
    1064                     'default' => '0',
    1065                 ],
    1066                 'freeDlvMinPVZ' => [
    1067                     'title' => __('Free delivery to pick-up points from, RUB', 'catapultodelivery') . '.',
    1068                     'description' => '',
    1069                     'desc_tip' => false,
    1070                     'type' => 'text',
    1071                     'default' => '0',
    1072                 ],
    10731372            ],
    10741373            'gabs'=>[
     
    11481447                    'type'    => 'checkbox',
    11491448                    'default' => 'yes'
     1449                ],
     1450                'isFitting'=>[
     1451                    'title'   => __('Fitting available', 'catapultodelivery'),
     1452                    'description' => __('Enable try-on feature. When you select try-on, the widget will only display delivery rates with try-on available', 'catapultodelivery'),
     1453                    'desc_tip' => true,
     1454                    'type'    => 'checkbox',
     1455                    'default' => 'no'
     1456                ],
     1457                'fittingDefaultEnabled'=>[
     1458                    'title'   => __('Fitting enabled by default', 'catapultodelivery'),
     1459                    'description' => __('By default, the try-on mode is enabled when the widget is launched', 'catapultodelivery'),
     1460                    'desc_tip' => true,
     1461                    'type'    => 'checkbox',
     1462                    'default' => 'no'
     1463                ],
     1464                'partialRedemptionEnabled'=>[
     1465                    'title'   => __('Enable partial buyback by default', 'catapultodelivery'),
     1466                    'description' => __('Enable the partial buyback service by default', 'catapultodelivery'),
     1467                    'desc_tip' => true,
     1468                    'type'    => 'checkbox',
     1469                    'default' => 'no'
    11501470                ],
    11511471            ],
     
    12251545                    'type'    => 'checkbox',
    12261546                    'default' => 'yes'
     1547                ],
     1548                'enLocalWidget' => [
     1549                    'title'   => __('Enable local version of widget', 'catapultodelivery'),
     1550                    'description' => __('Do not use this option', 'catapultodelivery') . '.',
     1551                    'desc_tip' => true,
     1552                    'type'    => 'checkbox',
     1553                    'default' => 'no'
    12271554                ],
    12281555
     
    13561683    }
    13571684
     1685    public function isFitting():bool
     1686    {
     1687        return ($this->settings['isFitting'] ?? false) === 'yes';
     1688    }
     1689
     1690    public function isFittingDefaultEnabled():bool
     1691    {
     1692        return ($this->settings['fittingDefaultEnabled'] ?? false) === 'yes';
     1693    }
     1694
     1695    public function isPartialRedemptionEnabled():bool
     1696    {
     1697        return ($this->settings['partialRedemptionEnabled'] ?? false) === 'yes';
     1698    }
     1699
    13581700    public function getOrderMapping():array
    13591701    {
     
    13651707    }
    13661708
     1709    public function getWarehouses():array
     1710    {
     1711        return $this->warehouses;
     1712    }
     1713
     1714    public function getDefaultWarehouseId():int
     1715    {
     1716        return intval($this->settings['wh_default_selected']);
     1717    }
     1718
     1719    public function getSenderWarehouse()
     1720    {
     1721        $defaultWhId = $this->getDefaultWarehouseId();
     1722        $selectedWH = null;
     1723        if ($defaultWhId > 0) {
     1724            foreach ($this->warehouses as $warehouse) {
     1725                if (intval($warehouse['id']) == $defaultWhId) {
     1726                    $selectedWH = $warehouse;
     1727                    break;
     1728                }
     1729            }
     1730        }
     1731        if ($defaultWhId == 0 || $selectedWH === null) {
     1732            //первый активный склад...
     1733            foreach ($this->warehouses as $warehouse) {
     1734                if ($warehouse['active'] === 'Y') {
     1735                    $selectedWH = $warehouse;
     1736                    break;
     1737                }
     1738            }
     1739        }
     1740        return $selectedWH;
     1741    }
     1742
    13671743}
  • catapultodelivery/trunk/libs/Wordpress/Controller/AbstractController.php

    r3417476 r3444321  
    3939        while ($error = $errorsCollections->getNext()) $errors[] = 'R' . $error->getCode() . ': ' . $error->getMessage();
    4040
    41         $errors[] = 'R' . $response->getError()->getCode() . ': ' . $response->getError()->getMessage();
     41        if ($response->getError()) {
     42            $errors[] = 'R' . $response->getError()->getCode() . ': ' . $response->getError()->getMessage();
     43        }
    4244        $this->errors = $errors;
    4345        return true;
  • catapultodelivery/trunk/libs/Wordpress/Controller/MainController.php

    r3417476 r3444321  
    44
    55use Ipol\Catapulto\Api\Entity\Response\ShipmentId;
     6use Ipol\Catapulto\Core\Order\Item;
    67use Ipol\Catapulto\Core\Order\Order;
    78use Ipol\Catapulto\Wordpress\CatapultoPlugin;
     
    4243    {
    4344        $response = $this->app->cargoCreate($order);
     45        if ($this->isResponseError($response)) return false;
     46        return $response->getResponse();
     47    }
     48
     49    public function createCargoByItem(Item $item)
     50    {
     51        $response = $this->app->cargoCreateByItem($item);
    4452        if ($this->isResponseError($response)) return false;
    4553        return $response->getResponse();
  • catapultodelivery/trunk/libs/Wordpress/Controller/OrderController.php

    r3417476 r3444321  
    1414use Ipol\Catapulto\Core\Order\Order;
    1515use Ipol\Catapulto\Core\Order\Payment;
     16use Ipol\Catapulto\Wordpress\CatapultoPlugin;
    1617use Ipol\Catapulto\Wordpress\CatapultoShippingMethod;
    1718use Ipol\Catapulto\Wordpress\DB\OrdersDB;
     
    2930        $shippingMethod = new CatapultoShippingMethod();
    3031        $moduleSettings = $shippingMethod->getAllSettings();
     32        $additionalServices = [];
    3133
    3234        $cOrder = new Order();
     
    6870        $cOrder->getAddressTo()->setCode($contactResponse->getResponse()->getId());
    6971
    70         //Sender
     72        //Sender && selected warehouse...
     73        $allWareHouses = $shippingMethod->getWarehouses();
     74        $selectedWarehouseId = intval($rateResultData['rate_param']['sender_warehouse_id'] ?? '0');
     75        $selectedWarehouse = null;
     76        foreach ($allWareHouses as $warehouse) {
     77            if (intval($warehouse['id']) == $selectedWarehouseId) {
     78                $selectedWarehouse = $warehouse;
     79                break;
     80            }
     81        }
     82        if ($selectedWarehouse === null) {
     83            $this->errors = [__('The dispatch warehouse was not found. You must select a warehouse and a new rate for the shipment', 'catapultodelivery')];
     84            return null;
     85        }
    7186        $senderAddress = (new Address())
    72             ->setCode($shippingMethod->getSenderId())
    73             ->setField('senderId', $shippingMethod->getSenderId())
    74             ->setField('senderCity', $shippingMethod->getSenderCity());
     87            ->setCode((string)$selectedWarehouse['contact_id'])
     88            ->setField('senderId', (string)$selectedWarehouse['contact_id'])
     89            ->setField('senderCity', (string)$selectedWarehouse['city_id']);
    7590
    7691        //Basket
     92        $cargoesIds = [];
     93        $rateCargoIds = $rateResultData['rate_param']['cargoes'];
     94        foreach ($rateCargoIds as $cargoId) {
     95            $cargoesIds[$cargoId] = false; //checked
     96        }
     97
     98        $customCargoData = unserialize($order->get_meta(CatapultoPlugin::ORDER_META_CARGO));
     99        if (!$customCargoData) {
     100            $this->errors = [__('I cant read the cargo details for this order', 'catapultodelivery')];
     101            return null;
     102        }
     103        //check cargoes...
     104        $errorMsg = '';
     105        foreach ($customCargoData as $crgData) {
     106            $cargoId = intval($crgData['ccargo_id']);
     107            $cargoesIds[$cargoId] = true;
     108
     109            foreach ($crgData['items'] as $itm) {
     110                $wei = intval($itm['weight']);
     111                $h = intval($itm['height']);
     112                $l = intval($itm['length']);
     113                $w = intval($itm['width']);
     114                if ($wei == 0) {
     115                    $errorMsg .= __('The weight of the product is not specified', 'catapultodelivery') . ' ['.$itm['id'].'] ' . $itm['name'] . PHP_EOL;
     116                }
     117                if ($h == 0) {
     118                    $errorMsg .= __('The height of the product is not set', 'catapultodelivery') . ' ['.$itm['id'].'] ' . $itm['name'] . PHP_EOL;
     119                }
     120                if ($l == 0) {
     121                    $errorMsg .= __('The product length is not specified.', 'catapultodelivery') . ' ['.$itm['id'].'] ' . $itm['name'] . PHP_EOL;
     122                }
     123                if ($w == 0) {
     124                    $errorMsg .= __('The width of the product is not set', 'catapultodelivery') . ' ['.$itm['id'].'] ' . $itm['name'] . PHP_EOL;
     125                }
     126            }
     127
     128        }
     129        $isCargoChecked = true;
     130        foreach ($cargoesIds as $checked) if (!$checked) $isCargoChecked = false;
     131        if (!$isCargoChecked) $errorMsg .= __('A mismatch of cargo units was detected. Please reselect the delivery option', 'catapultodelivery') . PHP_EOL;
     132
     133        $isValidCargoData = Calculator::validateCargoData($customCargoData, null, $order);
     134        if (!$isValidCargoData) $errorMsg .= __('A discrepancy was detected between the order basket and the package contents. You must delete the packages, recreate them, and select a new shipping calculation', 'catapultodelivery') . PHP_EOL;
     135        if ( $requestData['ctpt_is_fitting'] == 'Y' ) {
     136            $additionalServices[] = CatapultoShippingMethod::CTPT_SERVICE_FITTING;
     137            if (!($rateResultData['variant']['_isFitting'] ?? false)) $errorMsg .= __('The Fitting service is included, but the billing was made without this service. A new billing is required', '') . PHP_EOL;
     138        }
     139        if ($requestData['ctpt_is_pr'] == 'Y') {
     140            $additionalServices[] = CatapultoShippingMethod::CTPT_SERVICE_PR;
     141        }
     142
     143        if (!empty($errorMsg)) {
     144            $this->errors = [$errorMsg];
     145            return null;
     146        }
     147
    77148        $itemCollections = new ItemCollection();
    78         $cargoResult = Calculator::getCurrentCargoDataByOrder($order);
    79         /** @var Cargo $cargo */
    80         $cargo = $cargoResult['CARGO'];
     149        $cargo = Calculator::getCurrentCargoDataByOrder($order);
     150        $cargoComment = Calculator::getCargoComment();
    81151        $cargo->reset();
    82152        while ($el = $cargo->getNext()) {
    83153            $item = (new Item())
     154                ->setId($el->getId())
    84155                ->setName($el->getField('name'))
    85156                ->setQuantity($el->getQuantity())
     
    97168        $goods = new Goods();
    98169        $goods
    99             ->setWeight($cargoResult['WEI'])
    100             ->setWidth($cargoResult['W'])
    101             ->setLength($cargoResult['L'])
    102             ->setHeight($cargoResult['H'])
     170            ->setWeight($cargo->getWeight())
     171            ->setWidth($cargo->getWidth())
     172            ->setLength($cargo->getLength())
     173            ->setHeight($cargo->getHeight())
    103174        ;
     175
     176        $customCargo = [];
     177        foreach ($customCargoData as $crgData) {
     178            $cargoId = intval($crgData['ccargo_id']);
     179            if ($cargoId == 0) continue;
     180            $customCargo[$cargoId] = [
     181                'id' => $cargoId,
     182                'items' => [],
     183            ];
     184            foreach ($crgData['items'] as $itm) {
     185                $customCargo[$cargoId]['items'][] = [
     186                    'id' => intval($itm['id']),
     187                    'name' => $itm['name'],
     188                    'qty' => floatval($itm['quantity']),
     189                    'articul' => $itm['articul'],
     190                    'weight' => intval($itm['weight']),
     191                    'height' => intval($itm['height']),
     192                    'width' => intval($itm['width']),
     193                    'length' => intval($itm['length']),
     194                ];
     195            }
     196        }
    104197
    105198        //Payment
     
    139232            ->setField('deliveryPaySide','sender')
    140233            ->setField('additional_services', [])
     234            ->setField('cargoes_ids', $rateCargoIds)
     235            ->setField('customCargoData', $customCargo)
    141236        ;
    142237
    143238        if (
    144             ($moduleSettings['poaEnabled'] == 'yes')
    145             && ($rateResultData['variant']['operator'] == 'dellin')
     239            $selectedWarehouse['poa_enabled'] === 'Y'
     240            && $rateResultData['variant']['operator'] === 'dellin'
    146241        ) {
    147242            $cOrder
    148243                ->setField('sender_poa', true)
    149                 ->setField('from_name', $moduleSettings['poaFromName'])
    150                 ->setField('from_passport_series', $moduleSettings['poaFromPassportSeries'])
    151                 ->setField('from_passport_number', $moduleSettings['poaFromPassportNumber'])
    152                 ->setField('from_passport_date', $moduleSettings['poaFromPassportDate'])
    153                 ->setField('send_receiver_poa_email', $moduleSettings['poaSendReceiverEmail'])
     244                ->setField('from_name', $selectedWarehouse['poa_from_fio'])
     245                ->setField('from_passport_series', $selectedWarehouse['poa_from_p_series'])
     246                ->setField('from_passport_number', $selectedWarehouse['poa_from_p_number'])
     247                ->setField('from_passport_date', $selectedWarehouse['poa_from_p_date'])
     248                ->setField('send_receiver_poa_email', $selectedWarehouse['poa_from_email'])
    154249            ;
    155250        }
     
    158253        if ($isPod) {
    159254            if ($requestData['ctpt_deliveryPaySide'] == 'Y') {
    160                 $cOrder
    161                     ->setField('additional_services', ['pod_amount','cod_amount'])
    162                     ->setField('deliveryPaySide', 'receiver')
    163                 ;
    164             } else $cOrder->setField('additional_services', ['pod_amount']);
    165         }
     255                $cOrder->setField('deliveryPaySide', 'receiver');
     256                $additionalServices[] = CatapultoShippingMethod::CTPT_SERVICE_COD;
     257            }
     258            $additionalServices[] = CatapultoShippingMethod::CTPT_SERVICE_POD;
     259        }
     260        $cOrder->setField('additional_services', $additionalServices);
    166261
    167262        // for w2* tarifs
    168         $operatorSendType = $moduleSettings['widgetDeliveryFrom'];
    169         if (isset($moduleSettings['op_type_' . $rateResultData['variant']['operator'] ])) $operatorSendType = $moduleSettings['op_type_' . $rateResultData['variant']['operator'] ];
    170 
    171         if ($operatorSendType == 'warehouse') $cOrder->setField('sender_terminal_code', $moduleSettings['op_code_' . $rateResultData['variant']['operator'] ] );
     263        //$operatorSendType = $selectedWarehouse['delivery_from'];
     264        $whOperators = json_decode($selectedWarehouse['operators'], true);
     265        if (!$whOperators) $whOperators = [];
     266        if (isset($whOperators[$rateResultData['variant']['operator']])) {
     267            $operatorSendType = $whOperators[$rateResultData['variant']['operator']]['t'];
     268            if ($operatorSendType === CatapultoShippingMethod::CTPT_SENDDLVTYPE_WAREHOUSE)
     269                $cOrder->setField('sender_terminal_code', $whOperators[$rateResultData['variant']['operator']]['c'] );
     270        }
     271
     272        //goodsData
     273        $goodsDataResult = $this->app->shipmentGoodsCreate($cOrder);
     274        if ($this->isResponseError($goodsDataResult)) return null;
    172275
    173276        if ($isPod) {
     
    189292            'main_status' => '',
    190293            'main_status_display' => '',
    191             'weight' => $cargoResult['WEI'],
     294            'weight' => $cargo->getWeight(),
    192295            'price' => $goodsAmount,
    193296            'operator' => $rateResultData['variant']['operator'],
     
    203306            'receiver_house' => $receiverAddress->getHouse() ?? '',
    204307            'receiver_flat' => $receiverAddress->getFlat() ?? '',
    205             'description' => $cargoResult['COMMENT'],
     308            'description' => $cargoComment,
    206309            'with_insurance' => $needInsurance,
    207310            'insurance_cost' => $insuranceValue,
  • catapultodelivery/trunk/libs/Wordpress/DB/AbstractDB.php

    r3417476 r3444321  
    4848        $sql = $this->db->prepare("SELECT * FROM %i WHERE `id` = %d;", $this->fullTableName, $recId);
    4949        return $this->db->get_row($sql, 'ARRAY_A');
     50    }
     51
     52    public function getLastRecord(): ?array
     53    {
     54        $sql = $this->db->prepare("SELECT * FROM %i ORDER BY `id` DESC LIMIT 1", $this->fullTableName);
     55        return $this->db->get_row($sql, 'ARRAY_A');
     56    }
     57
     58    public function getLastRecordId(): int
     59    {
     60        $sql = $this->db->prepare("SELECT `id` FROM %i ORDER BY `id` DESC LIMIT 1", $this->fullTableName);
     61        $record = $this->db->get_row($sql, 'ARRAY_A');
     62        if (!$record) return 0;
     63        return intval($record['id']);
    5064    }
    5165
     
    113127    }
    114128
     129    public function deleteById(int $recId):void
     130    {
     131        $sql = $this->db->prepare("DELETE FROM %i WHERE `id` = %d", $this->fullTableName, $recId);
     132        $this->db->query($sql);
     133    }
     134
    115135}
  • catapultodelivery/trunk/libs/Wordpress/DB/DBTools.php

    r3417476 r3444321  
    6262            `receiver_phone`                  VARCHAR(150),
    6363            `receiver_email`                  VARCHAR(150),
    64            
     64
    6565            `receiver_street`                 VARCHAR(255),
    6666            `receiver_house`                  varchar(50),
    6767            `receiver_flat`                   varchar(50),
    68            
     68
    6969            `description`                     TEXT,
    7070            `with_insurance`                  BOOL,
     
    8080            `rate_result_id`                  INT(11) NOT NULL,
    8181            `terminal_code`                   VARCHAR(100),
    82            
     82
    8383            `comment` TEXT,
    8484            `dlv_pay_side` tinyint(1) unsigned NOT NULL DEFAULT '0',
    85            
     85
    8686            `updated` datetime,
    8787            PRIMARY KEY (`id`),
     
    9292        ) DEFAULT CHARSET={$this->db->charset};");
    9393
     94        $this->db->query("CREATE TABLE IF NOT EXISTS `{$this->db->get_blog_prefix()}catapulto_warehouses` (
     95            `id` int(11) unsigned NOT NULL auto_increment,
     96            `city_id` int(11) unsigned NOT NULL,
     97            `city_index` int(11) unsigned NOT NULL,
     98            `contact_id` int(11) unsigned NOT NULL,
     99            `city_name` varchar(250),
     100            `name` varchar(250),
     101            `delivery_from` varchar(30),
     102            `free_courier_from` varchar(30),
     103            `free_pickup_from` varchar(30),
     104            `poa_enabled` varchar(1) NOT NULL DEFAULT 'N',
     105            `poa_from_fio` varchar(200),
     106            `poa_from_p_series` varchar(20),
     107            `poa_from_p_number` varchar(20),
     108            `poa_from_p_date` varchar(20),
     109            `poa_from_email` varchar(100),
     110            `lat` varchar(12),
     111            `lon` varchar(12),
     112            `operators` text,
     113            `active` varchar(1) NOT NULL DEFAULT 'N',
     114
     115            `updated` datetime,
     116            PRIMARY KEY (`id`)
     117        ) DEFAULT CHARSET={$this->db->charset};");
     118
    94119    }
    95120
  • catapultodelivery/trunk/libs/Wordpress/DB/OrdersDB.php

    r3417476 r3444321  
    4848        $finalStatuses = CatapultoShippingMethod::getFinalStatuses();
    4949        $mask = implode( ', ', array_fill( 0, count( $finalStatuses ), '%s' ) );
    50         $sql = $this->db->prepare("SELECT * FROM %i WHERE (`tracking_status` IS NULL) OR (`tracking_status` NOT IN ({$mask}) );", $this->fullTableName, $finalStatuses);
     50        array_unshift($finalStatuses, $this->fullTableName);
     51        $sql = $this->db->prepare("SELECT * FROM %i WHERE (`tracking_status` IS NULL) OR (`tracking_status` NOT IN ({$mask}) );", ...$finalStatuses);
    5152        return $this->db->get_results($sql, 'ARRAY_A');
    5253    }
     
    5556    {
    5657        $mask = implode( ', ', array_fill( 0, count( $ids ), '%d' ) );
    57         $sql = $this->db->prepare("SELECT * FROM %i WHERE (`id` IN ({$mask}) )", $this->fullTableName, $ids);
     58        array_unshift($ids, $this->fullTableName);
     59        $sql = $this->db->prepare("SELECT * FROM %i WHERE (`id` IN ({$mask}) )", ...$ids);
    5860        return $this->db->get_results($sql, 'ARRAY_A');
    5961    }
  • catapultodelivery/trunk/libs/Wordpress/Frontend/AdminPages.php

    r3417476 r3444321  
    33namespace Ipol\Catapulto\Wordpress\Frontend;
    44
     5use Ipol\Catapulto\Core\Delivery\Cargo;
    56use Ipol\Catapulto\Wordpress\CatapultoPlugin;
    67use Ipol\Catapulto\Wordpress\CatapultoShippingMethod;
     
    1617    private static $moduleSettings = [];
    1718    private static $rateResultData = [];
     19    private static $warehouses = [];
     20    private static $selectedWarehouseId = 0;
     21    private static $senderWarehouse = [];
    1822
    1923    public static function renderOrderMetaBox()
     
    2327        $shippingMethod = self::$shippingMethod;
    2428        self::$moduleSettings  = $shippingMethod->getAllSettings();
     29        self::$warehouses = $shippingMethod->getWarehouses();
     30        self::$selectedWarehouseId = $shippingMethod->getDefaultWarehouseId();
     31        self::$senderWarehouse = $shippingMethod->getSenderWarehouse();
    2532        $order = wc_get_order();
    2633
     
    4047    private static function renderOrderSendMetabox(\WC_Order $order)
    4148    {
    42         $orderDefaultGabs = Calculator::getCurrentCargoDataByOrder($order);
     49        //Работа с грузоместами - здесь
     50        $customCargoData = unserialize($order->get_meta(CatapultoPlugin::ORDER_META_CARGO));
     51        $cargoComment = $order->get_meta(CatapultoPlugin::ORDER_META_CARGOCOMMENT);
     52        $isSingleProduct = true;
     53        $isCargoValid = true;
     54        if (!$customCargoData) {
     55            //create default cargo data...
     56            $cargoId = 0;
     57            if (
     58                isset(self::$rateResultData['rate_param'])
     59                && isset(self::$rateResultData['rate_param']['cargoes'])
     60                && is_array(self::$rateResultData['rate_param']['cargoes'])
     61                && count(self::$rateResultData['rate_param']['cargoes']) == 1
     62            ) $cargoId = self::$rateResultData['rate_param']['cargoes'][0];
     63
     64            $cargo = Calculator::getCurrentCargoDataByOrder($order);
     65            $cargoComment = Calculator::getCargoComment();
     66            $cargo
     67                ->setId((new \DateTime())->getTimestamp())
     68                ->setOrd($order->get_id())
     69                ->setCargoId($cargoId)
     70            ;
     71
     72            $order->update_meta_data(CatapultoPlugin::ORDER_META_CARGO, serialize([$cargo->toArray()]));
     73            $order->update_meta_data(CatapultoPlugin::ORDER_META_CARGOCOMMENT, $cargoComment);
     74            $order->save();
     75
     76            $isSingleProduct = $cargo->isSingleProduct();
     77
     78            $customCargoData = [$cargo];
     79        } else {
     80            //load CustomCargoData
     81            $cargoesData = $customCargoData;
     82            $customCargoData = [];
     83            $isCargoValid = Calculator::validateCargoData($cargoesData, null, $order);
     84            foreach ($cargoesData as $cargo) {
     85                $crg = new Cargo();
     86                $crg->fromArray($cargo);
     87                $crg
     88                    ->setCargoId(intval($cargo['ccargo_id']))
     89                    ->setId($cargo['id'])
     90                    ->setOrd($cargo['ord'])
     91                ;
     92                $customCargoData[] = $crg;
     93                if (!$crg->isSingleProduct()) $isSingleProduct = false;
     94            }
     95            if (count($customCargoData) > 1) $isSingleProduct = false;
     96        }
     97        $cargoesData = [];
     98        foreach ($customCargoData as $crg) $cargoesData[] = $crg->toArray();
    4399
    44100        $orderData = $order->get_data();
     
    54110            $isCod = true;
    55111            $serviceFilter = 'NP,COD';
    56             foreach (self::$rateResultData['variant']['additional_services'] as $service) {
    57                 if ($service['name'] == 'cod_amount') {
    58                     $codAmount = $service['cost'];
    59                     break;
     112            if (isset(self::$rateResultData['variant']['additional_services']))
     113                foreach (self::$rateResultData['variant']['additional_services'] as $service) {
     114                    if ($service['name'] == 'cod_amount') {
     115                        $codAmount = $service['cost'];
     116                        break;
     117                    }
    60118                }
    61             }
    62         }
    63 
    64         $defaultDeliveryFrom = self::$moduleSettings['widgetDeliveryFrom'];
    65         $inverceDeliveryTypes = [];
    66         $operatorsDB = new OperatorsDB();
    67         $allOperators = $operatorsDB->getAllByColumn('op_enabled','Y');
    68         foreach ($allOperators as $operator) {
    69             if (self::$moduleSettings['op_type_' . $operator['operator_id']] != $defaultDeliveryFrom) $inverceDeliveryTypes[] = $operator['operator_id'];
    70         }
    71         $inverceDeliveryTypesStr = implode("','",$inverceDeliveryTypes);
    72         if (empty($inverceDeliveryTypesStr)) $inverceDeliveryTypesStr = '[]';
    73         else $inverceDeliveryTypesStr = "['" . $inverceDeliveryTypesStr . "']";
     119        }
    74120
    75121        //get Order Meta Data
     
    83129
    84130        $pvzSender = '';
    85         if ( (self::$moduleSettings[ 'op_type_' . self::$rateResultData['variant']['operator'] ] ?? '') == 'warehouse' ) $pvzSender = '<p><b>' . __('Sender`s pickup point code', 'catapultodelivery') . '</b></p><p>' . self::$moduleSettings[ 'op_code_' . self::$rateResultData['variant']['operator'] ] . '</p>';
     131        if ( isset(self::$rateResultData['variant']['operator']) && (self::$moduleSettings[ 'op_type_' . self::$rateResultData['variant']['operator'] ] ?? '') == 'warehouse' ) $pvzSender = '<p><b>' . __('Sender`s pickup point code', 'catapultodelivery') . '</b></p><p>' . self::$moduleSettings[ 'op_code_' . self::$rateResultData['variant']['operator'] ] . '</p>';
    86132        $pvzReceiver = '';
    87133        if (isset(self::$rateResultData['Terminal']) && !empty(self::$rateResultData['Terminal'])) {
     
    130176        }
    131177
    132         $emptyRateData = [
    133             'dadata' => [
    134                 'data' => [],
    135             ],
    136             'variant' => [
    137                 'additional_services' => [],
    138                 'operator' => 'NotSet',
    139             ],
    140             'ctpt_params' => [
    141                 'isEmpty' => true,
    142             ],
    143         ];
    144         $str = json_encode($emptyRateData);
     178        $cargoLen = 0;
     179        $cargoHei = 0;
     180        $cargoWid = 0;
     181        $cargoWei = 0;
     182        if (count($customCargoData) > 0) {
     183            $cargoLen = $customCargoData[0]->getLength();
     184            $cargoHei = $customCargoData[0]->getHeight();
     185            $cargoWid = $customCargoData[0]->getWidth();
     186            $cargoWei = $customCargoData[0]->getWeight();
     187        }
     188
     189        //if rate empty...
     190        if (empty($receiverPostalCode)) {
     191            $receiverPostalCode = $order->get_shipping_postcode();
     192            if (empty($receiverPostalCode)) $receiverPostalCode = $order->get_billing_postcode();
     193        }
     194        if (empty($receiverCity)) {
     195            $receiverCity = $order->get_shipping_city();
     196            if (empty($receiverCity)) $receiverCity = $order->get_billing_city();
     197        }
     198
     199        $ctptServices = [];
     200        foreach ( (self::$rateResultData['variant']['additional_services'] ?? []) as $service ) {
     201            $ctptServices[] = [
     202                'name' => $service['name'],
     203                'cost' => $service['cost'],
     204            ];
     205        }
     206        $ctptServicesJs = json_encode($ctptServices, JSON_UNESCAPED_UNICODE);
     207
     208        $senderId = 0;
     209        $senderLocId = 0;
     210        $senderZip = 0;
     211        $senderCity = '';
     212        $selectedWhId = 0;
     213        $warehousesForAdm = [];
     214        if (!empty(self::$senderWarehouse)) {
     215            $senderId = intval(self::$senderWarehouse['contact_id']);
     216            $senderLocId = intval(self::$senderWarehouse['city_id']);
     217            $senderZip = self::$senderWarehouse['city_index'];
     218            $senderCity = self::$senderWarehouse['city_name'];
     219            $selectedWhId = intval(self::$senderWarehouse['id']);
     220        }
     221        if (
     222            isset(self::$rateResultData['rate_param'])
     223        ) {
     224            $savedWarehouseId = intval(self::$rateResultData['rate_param']['sender_warehouse_id'] ?? '0');
     225            if ($savedWarehouseId > 0) {
     226                $selectedWhId = $savedWarehouseId;
     227                foreach (self::$warehouses as $warehouse) {
     228                    if (intval($warehouse['id']) == $savedWarehouseId) {
     229                        $senderId = $warehouse['contact_id'];
     230                        $senderLocId = $warehouse['city_id'];
     231                        $senderZip = $warehouse['city_index'];
     232                        $senderCity = $warehouse['city_name'];
     233                    }
     234                    $warehousesForAdm[] = [
     235                        'id'=>intval($warehouse['id']),
     236                        'sid'=>intval($warehouse['contact_id']),
     237                        'lid'=>intval($warehouse['city_id']),
     238                        'zip'=>$warehouse['city_index'],
     239                        'city'=>$warehouse['city_name'],
     240                        'whname'=>$warehouse['name'],
     241                    ];
     242                }
     243            }
     244        }
    145245
    146246        $orderData = [
     
    152252            'phone'      => Tools::phoneValidator($order->get_billing_phone()),
    153253            'email'      => $order->get_billing_email(),
    154             'wei' => $orderDefaultGabs['WEI'],
    155             'wid' => $orderDefaultGabs['W'],
    156             'len' => $orderDefaultGabs['L'],
    157             'hei' => $orderDefaultGabs['H'],
    158             'cargoComment' => $orderDefaultGabs['COMMENT'],
     254            'wei' => $cargoWei,
     255            'wid' => $cargoWid,
     256            'len' => $cargoLen,
     257            'hei' => $cargoHei,
     258            'cargoComment' => $cargoComment,
     259            'customCargo' => json_encode($cargoesData),
     260            'customCargoValid' => $isCargoValid ? 'true' : 'false',
    159261            'receiverZip' => $receiverPostalCode,
    160262            'receiverCity' => $receiverCity,
     
    163265            'receiverFlat' => $receiverFlat,
    164266
    165             'senderId' => self::$moduleSettings['senderId'],
    166             'senderLocId' => self::$moduleSettings['senderLocalityId'],
    167             'senderZip' => self::$moduleSettings['senderZip'],
    168             'senderCity' => self::$moduleSettings['senderCity'],
     267            'senderId' => $senderId,
     268            'senderLocId' => $senderLocId,
     269            'senderZip' => $senderZip,
     270            'senderCity' => $senderCity,
    169271
    170272            'variantId' => self::$rateResultData['variant']['id'] ?? '',
     
    186288            'widgetDeliveryFrom' => self::$moduleSettings['widgetDeliveryFrom'],
    187289            'widgetMapMode' =>  (self::$moduleSettings['enMapOpenMode'] === 'courier') ? 'false' : 'true',
    188             'inverseOperators' => $inverceDeliveryTypesStr,
    189290            'isCard' => $isCard ? 'true' : 'false',
    190291            'isCash' => $isCash ? 'true' : 'false',
     
    198299
    199300            'isInsurance' => (self::$rateResultData['ctpt_params']['insurance'] ?? false) ? 'true' : 'false',
     301            'insuranceConfig' => floatval(self::$rateResultData['variant']['insurance_config'] ?? 0),
     302
     303            'isFitting' => (self::$rateResultData['variant']['_isFitting'] ?? false) ? 'true' : 'false',
     304            'isPR' => (self::$rateResultData['ctpt_params']['pr'] ?? false) ? 'true' : 'false',
     305            'basePrice' => floatval(self::$rateResultData['variant']['_priceWithoutAdditionalServices'] ?? 0),
     306            'isProdSingle' => $isSingleProduct ? 'true' : 'false',
     307
     308            'ctpt_services' => $ctptServicesJs,
     309
     310            //widget settings...
     311            'w_geo_data_empty_message' => self::$moduleSettings['geoEmptyMessage'] ?? '',
     312            'w_ws_api_domain' => ( (self::$moduleSettings['isTest'] ?? '') === 'yes' ) ? (self::$moduleSettings['customWSUrl'] ?? '') : '',
     313
     314            'warehouses' => json_encode($warehousesForAdm, JSON_UNESCAPED_UNICODE),
     315            'selectedwh' => $selectedWhId,
    200316
    201317        ];
  • catapultodelivery/trunk/libs/Wordpress/Frontend/CheckoutBlock.php

    r3417476 r3444321  
    88use Ipol\Catapulto\Wordpress\Controller\MainController;
    99use Ipol\Catapulto\Wordpress\DB\CartVariantsDB;
     10use Ipol\Catapulto\Wordpress\DB\WarehousesDB;
    1011use Ipol\Catapulto\Wordpress\Shipping\Calculator;
    1112use Ipol\Catapulto\Wordpress\Tools\Tools;
     
    4041        $settings = $shippingMethod->getAllSettings();
    4142        $cargo = Calculator::getCurrentCargoDataByCart();
    42         if (empty($cargo)) return [];
     43        if (!$cargo) return [];
     44        $cargoComment = Calculator::getCargoComment();
     45        $cargoAmount = Calculator::getCartAmount();
    4346
    4447        //get cart && delete current variant id
     
    5760        );
    5861
    59         $widgetDeliveryFrom = $settings['widgetDeliveryFrom'];
    60         $operatorsSettings = [];
    61         $inverseOperators = [];
    62         $freeDeliveryOperators = [];
    6362        $icons = [];
    6463        $companyIcons = $mainController->getCompanyIcons();
     
    6766            while ($el = $elements->getNext()) {
    6867                $icons[$el->getOperatorId()] = $el->getIcon();
    69 
    70                 $operatorSetting = [
    71                     'operator' => $el->getOperatorId(),
    72                     'inverse_delivery_type' => false,
    73                     'free_delivery' => false,
    74                 ];
    75 
    76                 if ($settings['op_type_' . $el->getOperatorId()] != $widgetDeliveryFrom ) {
    77                     $inverseOperators[] = $el->getOperatorId();
    78                     $operatorSetting['inverse_delivery_type'] = true;
    79                 }
    80 
    81                 if ($settings['op_free_' . $el->getOperatorId()] === 'yes' ) {
    82                     $freeDeliveryOperators[] = $el->getOperatorId();
    83                     $operatorSetting['free_delivery'] = true;
    84                 }
    85                 $operatorsSettings[] = $operatorSetting;
    8668            }
    8769        }
     
    9072        if ($widgetDeliveryTypes == 'All') $widgetDeliveryTypes = false;
    9173
     74        //getWarehouseData
     75        $localityId = 0;
     76        $zip = '';
     77        $cityFrom = '';
     78        $selectedWH = $shippingMethod->getSenderWarehouse();
     79        if (is_array($selectedWH)) {
     80            $localityId = $selectedWH['city_id'];
     81            $zip = $selectedWH['city_index'];
     82            $cityFrom = $selectedWH['city_name'];
     83        }
     84
    9285        $params = [
    9386            'isTestMode' => $settings['isTest'] === 'yes',
    9487            'servicePath' => '/?rest_route=/catapultodelivery/widgethandler',
    95             'senderLocalityId' => $settings['senderLocalityId'],
    96             'senderZip' => $settings['senderZip'],
    97             'senderCityFrom' => $settings['senderCity'],
     88            'senderLocalityId' => $localityId,
     89            'senderZip' => $zip,
     90            'senderCityFrom' => $cityFrom,
    9891            'dadataToken' => $settings['dadataApikey'],
    99             'cargoHeight' => $cargo['H'],
    100             'cargoLength' => $cargo['L'],
    101             'cargoWidth' => $cargo['W'],
    102             'cargoWeight' => $cargo['WEI'],
    103             'cargoComment' => $cargo['COMMENT'],
    104             'insuredValue' => $cargo['CARGO']->getTotalPrice()->getAmount(),
     92            'cargoHeight' => $cargo->getHeight(),
     93            'cargoLength' => $cargo->getLength(),
     94            'cargoWidth' => $cargo->getWidth(),
     95            'cargoWeight' => $cargo->getWeight(),
     96            'cargoComment' => $cargoComment,
     97            'insuredValue' => $cargoAmount,
    10598            'needInsurance' => $settings['mindEnsurance'] === 'yes',
    10699
     
    109102
    110103            'widgetDeliveryTypes' => $widgetDeliveryTypes,
    111             'deliveryType' => $settings['widgetDeliveryFrom'],
    112             'inverseOperators' => $inverseOperators,
    113             'freeDeliveryOperators' => $freeDeliveryOperators,
    114             'operatorsSettings' => $operatorsSettings,
    115104            'dayShift' => intval($settings['termIncrease']),
    116105            'mapOpenMode' => $settings['enMapOpenMode'] === 'map',
     
    124113            //
    125114            'geoEmptyMessage' => $settings['geoEmptyMessage'] ?? '',
    126             'freeDlvMinCourier' => floatval($settings['freeDlvMinCourier']) ?? 0,
    127             'freeDlvMinPVZ' => floatval($settings['freeDlvMinPVZ']) ?? 0,
     115
     116            //fitting
     117            'isFitting' => $settings['isFitting'] === 'yes',
     118            'fittingDefaultEnabled' => $settings['fittingDefaultEnabled'] === 'yes',
     119            'partialRedemptionEnabled' => $settings['partialRedemptionEnabled'] === 'yes',
    128120
    129121        ];
  • catapultodelivery/trunk/libs/Wordpress/Rest/RestHandler.php

    r3417476 r3444321  
    33namespace Ipol\Catapulto\Wordpress\Rest;
    44
     5use Ipol\Catapulto\Api\BadResponseException;
     6use Ipol\Catapulto\Core\Delivery\Cargo;
     7use Ipol\Catapulto\Core\Delivery\CargoItem;
     8use Ipol\Catapulto\Core\Entity\Money;
    59use Ipol\Catapulto\Core\Order\Address;
    610use Ipol\Catapulto\Core\Order\Item;
     
    913use Ipol\Catapulto\Wordpress\CatapultoPlugin;
    1014use Ipol\Catapulto\Wordpress\CatapultoShippingMethod;
     15use Ipol\Catapulto\Wordpress\Controller\AbstractController;
    1116use Ipol\Catapulto\Wordpress\Controller\MainController;
    1217use Ipol\Catapulto\Wordpress\DB\CartVariantsDB;
    1318use Ipol\Catapulto\Wordpress\DB\OperatorsDB;
    1419use Ipol\Catapulto\Wordpress\DB\OrdersDB;
     20use Ipol\Catapulto\Wordpress\DB\WarehousesDB;
    1521use Ipol\Catapulto\Wordpress\Factory\ControllerFactory;
    1622use Ipol\Catapulto\Wordpress\Tools\Variables;
     
    1824class RestHandler
    1925{
     26
     27    private static $errors = [];
    2028
    2129    public static function widgetHandler($request)
     
    4250                if (empty($requestData)) return new \WP_REST_Response(['error'=>'CreateRate: DATA_CORRUPTED'], 200);
    4351
     52                $selectedWHIdForce = intval($requestData['warehouseId'] ?? 0);
     53                $selectedWh = null;
     54                $allWarehouses = $shippingMethod->getWarehouses();
     55                if ($selectedWHIdForce > 0) {
     56                    foreach ($allWarehouses as $warehouse) {
     57                        if (intval($warehouse['id']) == $selectedWHIdForce) {
     58                            $selectedWh = $warehouse;
     59                            break;
     60                        }
     61                    }
     62                } else {
     63                    $defaultWH = null;
     64
     65                    $geoLat = floatval($requestData['dadata_selected_choice']['geo_lat'] ?? '0');
     66                    $geoLon = floatval($requestData['dadata_selected_choice']['geo_lon'] ?? '0');
     67                    $distance = 0;
     68                    foreach ($allWarehouses as $warehouse) {
     69                        if ($warehouse['active'] != 'Y') continue; //склад не активен
     70                        $whLat = floatval($warehouse['lat']);
     71                        $whLon = floatval($warehouse['lon']);
     72                        if ($whLat == 0 || $whLon == 0) continue; //Отсутствуют координаты склада
     73                        if (intval($warehouse['id']) == $shippingMethod->getDefaultWarehouseId()) $defaultWH = $warehouse;
     74
     75                        //Определяем ближайший склад
     76                        if ($geoLat > 0 && $geoLon > 0) {
     77                            $a1 = deg2rad($geoLat);
     78                            $b1 = deg2rad($geoLon);
     79                            $a2 = deg2rad($whLat);
     80                            $b2 = deg2rad($whLon);
     81                            $calculatedDistance = 12742016 * asin(sqrt(pow(sin(($a2 - $a1) / 2), 2) + cos($a2) * cos($a1) * pow(sin(($b2 - $b1) / 2), 2)));
     82                            if (($calculatedDistance < $distance) || ($distance === 0)) {
     83                                $selectedWh  = $warehouse;
     84                                $distance = $calculatedDistance;
     85                            }
     86                        }
     87                    }
     88                    if ($selectedWh === null) $selectedWh = $defaultWH;
     89                    if ($selectedWh === null) {
     90                        //error - WH for tarif not selected....
     91                        return new \WP_REST_Response(['error'=>'CreateRate: CANT SELECT WH'], 200);
     92                    }
     93                }
     94
     95                $invSendType           = [];
     96                $freeDeliveryOperators = [];
     97                $operatorsData = json_decode($selectedWh['operators'], true);
     98                if (!$operatorsData) $operatorsData = [];
     99                foreach ($operatorsData as $code => $operator) {
     100                    if ($operator['f']) $freeDeliveryOperators[] = $code;
     101                    if ($operator['t'] != $selectedWh['delivery_from']) $invSendType[] = $code;
     102                }
     103
     104                $whParams = [
     105                    'delivery_type' => $selectedWh['delivery_from'],
     106                    'free_delivery_min_courier' => intval($selectedWh['free_courier_from']),
     107                    'free_delivery_min_pvz' => intval($selectedWh['free_pickup_from']),
     108                    'free_delivery_operators' => $freeDeliveryOperators,
     109                    'inverse_delivery_type_for_operators' => $invSendType,
     110                    'warehouseCustom' => false,
     111                ];
     112
    44113                $ignoredSettlementTypes = Variables::getIgnoredSettlementTypes();
    45114                $receiverCity = $requestData['dadata_selected_choice']['settlement'] ?? '';
     
    74143
    75144                $sender = (new Address())
    76                     ->setZip($shippingMethod->getSenderZip())
    77                     ->setField('cityFrom', $shippingMethod->getSenderCity())
    78                     ->setField('locality_id', $shippingMethod->getSenderLocId());
    79 
    80                 $itemCollection = new ItemCollection();
     145                    ->setZip($selectedWh['city_index'])
     146                    ->setField('cityFrom', $selectedWh['city_name'])
     147                    ->setField('locality_id', $selectedWh['city_id']);
     148
     149                self::$errors = [];
    81150                if (!empty($requestData['cargo_data'])) {
    82                     $item = (new Item())
    83                         ->setField('comment', $requestData['cargo_data']['cargo_comment'] ?? 'empty')
    84                         ->setField('type', $requestData['delivery_type'] ?? 'parcel');
    85                     ;
    86                     if (isset($requestData['cargo_data']['width']) && !empty($requestData['cargo_data']['width'])) $item->setWidth( intval($requestData['cargo_data']['width']) );
    87                     if (isset($requestData['cargo_data']['height']) && !empty($requestData['cargo_data']['height'])) $item->setHeight( intval($requestData['cargo_data']['height']) );
    88                     if (isset($requestData['cargo_data']['length']) && !empty($requestData['cargo_data']['length'])) $item->setLength( intval($requestData['cargo_data']['length']) );
    89                     if (isset($requestData['cargo_data']['weight']) && !empty($requestData['cargo_data']['weight'])) $item->setWeight( intval($requestData['cargo_data']['weight']) );
    90                     if (isset($requestData['cargo_data']['quantity']) && !empty($requestData['cargo_data']['quantity'])) $item->setQuantity( intval($requestData['cargo_data']['quantity']) );
    91                     $itemCollection->add($item);
     151                    $cargoSubDataNames     = ['cargo_comment', 'height', 'length', 'width', 'quantity', 'weight'];
     152                    $cargoRequestArrayData = $requestData['cargo_data'];
     153                    $isSingle = false;
     154                    foreach ($cargoSubDataNames as $name) if (isset($cargoRequestArrayData[$name])) $isSingle = true;
     155                    $cargoIds = [];
     156                    if (
     157                        is_array($cargoRequestArrayData)
     158                        && (count($cargoRequestArrayData) > 0)
     159                        && !$isSingle
     160                    ) {
     161                        //Если это существующий заказ - смотрим - есть ли данные по сохраненным грузоместам, т.к. если это многоместный заказ - скорее всего есть.
     162                        $orderId = intval($cargoRequestArrayData[0]['ord']);
     163                        $savedCargoData = [];
     164                        try {
     165                            $wcOrder = new \WC_Order($orderId);
     166                            $savedCargoData = unserialize($wcOrder->get_meta(CatapultoPlugin::ORDER_META_CARGO));
     167                            if (!$savedCargoData) $savedCargoData = [];
     168                        } catch (\Exception $e) {
     169
     170                        }
     171
     172                        foreach ($cargoRequestArrayData as $cCata) {
     173                            $cargoId = self::createCatapultoCargo($mainController, $cCata, $data['delivery_type'] ?? 'parcel');
     174                            if (!$cargoId && !empty(self::$errors)) return new \WP_REST_Response(['error'=>self::$errors[0]], 200);
     175                            if ($cargoId !== false) $cargoIds[] = $cargoId;
     176
     177                            //save to custom cargo data...
     178                            foreach ($savedCargoData as $key => $crg) {
     179                                if ($crg['id'] == $cCata['crg_id']) {
     180                                    $savedCargoData[$key]['ccargo_id'] = $cargoId;
     181                                    break;
     182                                }
     183                            }
     184                        }
     185
     186                        //save info
     187                        if ($wcOrder) {
     188                            $wcOrder->update_meta_data(CatapultoPlugin::ORDER_META_CARGO, serialize($savedCargoData));
     189                            $wcOrder->save();
     190                        }
     191                    } else {
     192                        $cargoId = self::createCatapultoCargo($mainController, $cargoRequestArrayData, $data['delivery_type'] ?? 'parcel');
     193                        if (!$cargoId && !empty(self::$errors)) return new \WP_REST_Response(['error'=>self::$errors[0]], 200);
     194                        $cargoIds = [$cargoId];
     195                        //$cargoItem = self::createCargoItem($cargoRequestArrayData, $data['delivery_type'] ?? 'parcel');
     196                        //if ($cargoItem) $itemCollection->add($cargoItem);
     197                    }
     198
     199
    92200                }
    93201
    94202                $order = (new Order())
    95203                    ->setAddressFrom($sender)
    96                     ->setAddressTo($receiver)
    97                     ->setItems($itemCollection);
    98 
    99                 $cargoData = $mainController->createCargo($order);
    100                 if (!$cargoData) return new \WP_REST_Response(['error'=>$mainController->getFirstError()], 200);
    101                 if (empty($cargoData->getId())) return new \WP_REST_Response(['error'=>'Cargo: empty data'], 200);
    102                 $order->setField('cargoes',[$cargoData->getId()]);
     204                    ->setAddressTo($receiver);
     205
     206                $order->setField('cargoes',$cargoIds);
    103207
    104208                $iconData = [];
     
    111215
    112216                $order->setField('dadata_variant', $requestData['dadata_selected_choice']);
    113                 if ($shippingMethod->getSenderId() > 0) $order->setField('sender_contact_id', $shippingMethod->getSenderId());
     217                if (intval($selectedWh['contact_id']) > 0) $order->setField('sender_contact_id', intval($selectedWh['contact_id']));
    114218                if (isset($requestData['pickup_days_shift'])) $order->setField('pickup_days_shift', $requestData['pickup_days_shift']);
    115219
     
    122226                    'locations' => [
    123227                        'sender'  => [
    124                             'locality_id' => $shippingMethod->getSenderLocId(),
    125                             'zip'         => $shippingMethod->getSenderZip(),
     228                            'locality_id' => $selectedWh['city_id'],
     229                            'contact_id'  => intval($selectedWh['contact_id']),
     230                            'zip'         => $selectedWh['city_index'],
     231                            'warehouse_id'=> $selectedWh['id'],
    126232                        ],
    127233                        'contact' => [
     
    130236                        ],
    131237                    ],
     238                    'multiWarehouse' => $whParams,
    132239                    'params'    => [
    133240                        'sender_locality_id'   => $shippingMethod->getSenderLocId(),
     241                        'sender_warehouse_id'  => $selectedWh['id'],
     242                        'sender_contact_id'    => $selectedWh['contact_id'],
    134243                        'receiver_locality_id' => $order->getAddressTo()->getField('locality_id'),
    135                         'cargoes'             => [$cargoData->getId()]
     244                        'cargoes'             => $cargoIds
    136245                    ],
    137246                    'icons' => $iconData
     
    429538    }
    430539
     540    //Cargoes
     541    public static function calcCargoDims($request)
     542    {
     543        $requestData = $request->get_params();
     544        $cargoData = json_decode($requestData['crg'], true);
     545        if (!$cargoData) return new \WP_REST_Response(['res'=>false], 200);
     546
     547        $coreCargo = new Cargo();
     548        $coreCargo->fromArray($cargoData)->calculateDimensions(true);
     549
     550        return new \WP_REST_Response([
     551            'res'=>true,
     552            'l' => $coreCargo->getLength(),
     553            'w' => $coreCargo->getWidth(),
     554            'h' => $coreCargo->getHeight(),
     555        ], 200);
     556    }
     557
     558    public static function cargoSave($request)
     559    {
     560        $requestData = $request->get_params();
     561        $orderId = intval($requestData['order_id']);
     562        if ($orderId == 0) return new \WP_REST_Response(['res'=>false, 'e'=>'NoOrder'], 200);
     563        try {
     564            $order = new \WC_Order($orderId);
     565        } catch (\Exception $e) {
     566            return new \WP_REST_Response(['res'=>false, 'e'=>'NoOrder'], 200);
     567        }
     568
     569        $crgData = json_decode($requestData['crg'], true);
     570        if (!$crgData) return new \WP_REST_Response(['res'=>false, 'e'=>'corrupted'], 200);
     571
     572        $customCargoData = [];
     573        foreach ($crgData as $cData) {
     574            $cargo = (new Cargo())
     575                ->setId($cData['id'])
     576                ->setCargoId(intval($cData['cargoId']))
     577                ->setOrd($orderId)
     578                ->setLength(intval($cData['length']))
     579                ->setHeight(intval($cData['height']))
     580                ->setWidth(intval($cData['width']))
     581                ->setWeight(intval($cData['weight']))
     582            ;
     583
     584            foreach ($cData['items'] as $itemdata) {
     585                $itm = (new CargoItem())
     586                    ->setId($itemdata['id'])
     587                    ->setName($itemdata['name'])
     588                    ->setArticul($itemdata['articul'])
     589
     590                    ->setHeight(intval(floatval($itemdata['height'])))
     591                    ->setWidth(intval(floatval($itemdata['width'])))
     592                    ->setLength(intval(floatval($itemdata['length'])))
     593                    ->setWeight(floatval($itemdata['weight']))
     594                    ->setQuantity(floatval($itemdata['quantity']))
     595
     596                    ->setCost(new Money( floatval($itemdata['price']['amount']) ))
     597                    ->setPrice(new Money( floatval($itemdata['price']['amount']) ))
     598                    ->setField('name', $itemdata['name'])
     599                    ->setField('sku', $itemdata['variantId'])
     600                    ->setField('dimEmpty', false)
     601                ;
     602                $cargo->add($itm);
     603            }
     604            $customCargoData[] = $cargo;
     605        }
     606
     607        $cargoesData = [];
     608        foreach ($customCargoData as $crg) $cargoesData[] = $crg->toArray();
     609
     610        $order->update_meta_data(CatapultoPlugin::ORDER_META_CARGO, serialize($cargoesData));
     611        $order->update_meta_data('ctpt_ratedata', serialize([]));
     612        $order->save();
     613
     614        return new \WP_REST_Response(['res'=>true], 200);
     615    }
     616
     617    public static function cargoClear($request)
     618    {
     619        $requestData = $request->get_params();
     620        $orderId = intval($requestData['order_id']);
     621        if ($orderId == 0) return new \WP_REST_Response(['res' => false, 'e' => 'NoOrder'], 200);
     622        try {
     623            $order = new \WC_Order($orderId);
     624        } catch (\Exception $e) {
     625            return new \WP_REST_Response(['res' => false, 'e' => 'NoOrder'], 200);
     626        }
     627
     628        $order->update_meta_data(CatapultoPlugin::ORDER_META_CARGO, '');
     629        $order->update_meta_data('ctpt_ratedata', serialize([]));
     630        $order->save();
     631
     632        return new \WP_REST_Response(['res'=>true], 200);
     633    }
     634
    431635    /////// For old WP versions
    432636    //save ctpt rate result from checkout page
     
    453657
    454658
     659
     660    private static function createCatapultoCargo(
     661        $controler,
     662        $cargoData,
     663        $deliveryType = 'parcel'
     664    ) {
     665        $cargoSubDataNames = [/*'cargo_comment',*/ 'height', 'length', 'width', 'quantity', 'weight'];
     666        foreach ($cargoSubDataNames as $name) {
     667            if (!isset($cargoData[$name])) return false; //not valid!
     668            if (empty($cargoData[$name])) return false;
     669        }
     670        $cargoItem = (new Item())
     671            ->setWeight((int)$cargoData['weight']) //граммы
     672            ->setWidth((int)$cargoData['width']) //мм
     673            ->setLength((int)$cargoData['length']) //мм
     674            ->setHeight((int)$cargoData['height']) //мм
     675            ->setQuantity((int)$cargoData['quantity']) //мм
     676            ->setField('comment', $cargoData['cargo_comment'] ?? 'empty')
     677            ->setField('type', $deliveryType)// тип отправления ['docs', 'parcel']
     678        ;
     679
     680        $cargoResult = $controler->createCargoByItem($cargoItem);
     681        if (!$cargoResult) {
     682            self::$errors[] = $controler->getFirstError();
     683            return null;
     684        }
     685        if (empty($cargoResult->getId())) {
     686            self::$errors[] = 'Cargo: empty data';
     687            return null;
     688        }
     689
     690        return $cargoResult->getId();
     691    }
     692
    455693}
  • catapultodelivery/trunk/libs/Wordpress/Shipping/Calculator.php

    r3417476 r3444321  
    66use Ipol\Catapulto\Core\Delivery\CargoItem;
    77use Ipol\Catapulto\Core\Entity\Money;
     8use Ipol\Catapulto\Wordpress\CatapultoPlugin;
    89use Ipol\Catapulto\Wordpress\CatapultoShippingMethod;
    910
     
    1213    const API_DIMENSION_UNIT = 'mm';
    1314    const API_WEIGHT_UNIT = 'g';
     15
     16    private static $cargoComment = '';
     17    private static $cartAmount = 0;
    1418
    1519    public static function getDefaultGabs():array
     
    3539     * Для расчета доставки виджетом Катапульто - подготовка данных расчета - параметров грузоместа
    3640     */
    37     public static function getCurrentCargoDataByCart():array
    38     {
    39         if (!WC()->cart) return [];
    40         $cargoData = self::getCargo( WC()->cart->get_cart() );
    41         $cargo = $cargoData['cargo'];
    42         $cargoComment = $cargoData['comment'];
    43 
    44         $dims = $cargo->getDimensions();
    45         $wei = $cargo->getWeight();
    46 
    47         return array_merge($dims,[
    48             'CARGO' => $cargo,
    49             'WEI'=>$wei,
    50             'TOTAL' => floatval(WC()->cart->get_subtotal()),
    51             'COMMENT' => $cargoComment
    52         ]);
    53     }
    54 
    55     public static function getCurrentCargoDataByOrder(\WC_Order $order):array
    56     {
    57         $cargoData = self::getCargo( $order->get_items() );
    58         $cargo = $cargoData['cargo'];
    59         $cargoComment = $cargoData['comment'];
    60 
    61         $dims = $cargo->getDimensions();
    62         $wei = $cargo->getWeight();
    63 
    64         return array_merge($dims,[
    65             'CARGO' => $cargo,
    66             'WEI'=>$wei,
    67             'COMMENT' => $cargoComment
    68         ]);
    69     }
    70 
    71     private static function getCargo($items)
     41    public static function getCurrentCargoDataByCart():?Cargo
     42    {
     43        if (!WC()->cart) return null;
     44        self::$cartAmount = WC()->cart->get_subtotal();
     45        return self::getCargo( WC()->cart->get_cart() );
     46    }
     47
     48    public static function getCurrentCargoDataByOrder(\WC_Order $order):Cargo
     49    {
     50        self::$cartAmount = $order->get_subtotal();
     51        return self::getCargo( $order->get_items() );
     52    }
     53
     54    private static function getCargo($items): Cargo
    7255    {
    7356
     
    7760        $cargoComment = '';
    7861
    79         if ($gabsSettings['MODE'] == 'O') {
    80             $itemsPrices = 0;
     62        if ($gabsSettings['MODE'] == CatapultoPlugin::DEFMODE_O) {
     63            //$itemsPrices = 0;
    8164            $hasEmpty = false;
    82             $orderCargo = new Cargo();
     65            //$orderCargo = new Cargo();
    8366            foreach ( $items as $item ) {
    8467                $product = null;
     
    9982                    || ($len == 0)
    10083                ) $isEmpty = true;
    101                 if (!$isEmpty) {
    102                     $cargoItem = (new CargoItem())
    103                         ->setHeight($hei)
    104                         ->setWidth($wid)
    105                         ->setLength($len)
    106                         ->setWeight($wei)
    107                         ->setQuantity($qty)
    108                         ->setPrice(new Money( floatval($product->get_price()) ))
    109                         ->setField('name', $product->get_name())
    110                         ->setField('sku', empty($product->get_sku()) ? '' : $product->get_sku());
    111                     $orderCargo->add($cargoItem);
    112                 } else $hasEmpty = true;
    113 
    114                 $itemsPrices += floatval($product->get_price()) * floatval($item['quantity']);
     84                if ($isEmpty) $hasEmpty = true;
     85
     86                $cargoItem = (new CargoItem())
     87                    ->setId($product->get_id())
     88                    ->setHeight($hei)
     89                    ->setWidth($wid)
     90                    ->setLength($len)
     91                    ->setWeight($wei)
     92                    ->setQuantity($qty)
     93                    ->setName($product->get_name())
     94                    ->setCost(new Money( floatval($product->get_price()) ))
     95                    ->setPrice(new Money( floatval($product->get_price()) ))
     96                    ->setField('name', $product->get_name())
     97                    ->setArticul('')
     98                    ->setField('sku', empty($product->get_sku()) ? '' : $product->get_sku())
     99                    ->setField('dimEmpty', $isEmpty)
     100                ;
     101                $cargo->add($cargoItem);
     102
    115103                $cargoComment .= $product->get_name() . '('.floatval($item['quantity']).');';
    116104            }
    117105
    118106            if ($hasEmpty) {
    119                 $dims = $orderCargo->getDimensions();
    120                 $wei = $orderCargo->getWeight();
    121 
    122                 $cargoItem = (new CargoItem())
    123                     ->setHeight( max($gabsSettings['HEI'], $dims['H']) )
     107                $dims = $cargo->getDimensions();
     108                $wei = $cargo->getWeight();
     109
     110                $cargo
     111                    ->setWeight(max($gabsSettings['WEI'], $wei))
    124112                    ->setWidth( max($gabsSettings['WID'], $dims['W']) )
    125113                    ->setLength( max($gabsSettings['LEN'], $dims['L']) )
    126                     ->setWeight( max($gabsSettings['WEI'], $wei) )
    127                     ->setQuantity(1)
    128                     ->setPrice(new Money( $itemsPrices ))
    129                     ->setField('name', 'order_calculated_gabs')
    130                     ->setField('sku', '');
    131                 $cargo->add($cargoItem);
    132 
    133             } else $cargo = $orderCargo;
     114                    ->setHeight( max($gabsSettings['HEI'], $dims['H']) )
     115                ;
     116            } else {
     117                $cargo->calculateDimensions(true);
     118                $cargo->setWeight($cargo->getWeight());
     119            }
    134120
    135121        } else {
     
    155141                ) $isEmpty = true;
    156142
    157                 if ($isEmpty && ($gabsSettings['MODE'] == 'G')) {
     143                if ($isEmpty && ($gabsSettings['MODE'] == CatapultoPlugin::DEFMODE_G)) {
    158144                    $wei = $gabsSettings['WEI'];
    159145                    $len = $gabsSettings['LEN'];
     
    164150                $cargoComment .= $product->get_name()."(${qty});";
    165151                $cargoItem = (new CargoItem())
     152                    ->setId($product->get_id())
    166153                    ->setHeight($hei)
    167154                    ->setWidth($wid)
     
    169156                    ->setWeight($wei)
    170157                    ->setQuantity($qty)
     158                    ->setName($product->get_name())
     159                    ->setCost(new Money( floatval($product->get_price()) ))
    171160                    ->setPrice(new Money( floatval($product->get_price()) ))
    172161                    ->setField('name', $product->get_name())
    173                     ->setField('sku', empty($product->get_sku()) ? '' : $product->get_sku());
     162                    ->setArticul('')
     163                    ->setField('sku', empty($product->get_sku()) ? '' : $product->get_sku())
     164                    ->setField('dimEmpty', $isEmpty)
     165                ;
    174166                $cargo->add($cargoItem);
    175167            }
    176         }
    177 
    178         return [
    179             'cargo' => $cargo,
    180             'comment' => $cargoComment,
    181         ];
     168            $cargo->calculateDimensions(true);
     169            $cargo->setWeight($cargo->getWeight());
     170        }
     171
     172        self::$cargoComment = $cargoComment;
     173
     174        return $cargo;
     175    }
     176
     177    public static function getCargoComment(): string
     178    {
     179        return self::$cargoComment;
     180    }
     181
     182    public static function getCartAmount(): int
     183    {
     184        return self::$cartAmount;
     185    }
     186
     187    public static function validateCargoData(array $customCargoData, Cargo $cargo = null, \WC_Order $order = null): bool
     188    {
     189        if (!$cargo && !$order) throw new \Exception('Cant validate CargoData, Cargo or WCOrder is missing');
     190        if (!$cargo) $cargo = self::getCurrentCargoDataByOrder($order);
     191
     192        $orderItems = [];
     193        $cargo->reset();
     194        while ($itm = $cargo->getNext()) {
     195            $orderItems[] = [
     196                'id' => intval($itm->getId()),
     197                'sku' => $itm->getField('sku') ?? '',
     198                'qty' => floatval($itm->getQuantity()),
     199                'cqty' => 0,
     200            ];
     201        }
     202
     203        foreach ($customCargoData as $customCargoItem) {
     204            foreach ($customCargoItem['items'] as $item) {
     205                $itemSku = $item['fields']['sku'] ?? '';
     206                $itemId = intval($item['id']);
     207                $itemQty = floatval($item['quantity']);
     208                $isExist = false;
     209                foreach ($orderItems as &$orderItem) {
     210                    if (
     211                        $orderItem['id'] == $itemId
     212                        && ($orderItem['sku'] == $itemSku)
     213                    ) {
     214                        $orderItem['cqty'] += $itemQty;
     215                        $isExist = true;
     216                    }
     217                }
     218                unset($orderItem);
     219                if (!$isExist) $orderItems[] = [
     220                    'id' => $itemId,
     221                    'sku' => $itemQty,
     222                    'qty' => 0,
     223                    'cqty' => $itemQty,
     224                ];
     225            }
     226
     227        }
     228
     229        $isValid = true;
     230        foreach ($orderItems as $orderItem) {
     231            if ($orderItem['qty'] != $orderItem['cqty']) $isValid = false;
     232        }
     233
     234        return $isValid;
    182235    }
    183236
  • catapultodelivery/trunk/libs/Wordpress/Tools/TemplateRender.php

    r3417476 r3444321  
    2020    {
    2121        echo wp_kses($content, [
    22             'div'=>[ 'class'=>[], 'style'=>[] ],
     22            'div'=>[ 'class'=>[], 'style'=>[], 'id'=>[], ],
    2323            'label' => [ 'for' => [], 'class' => [], 'style' => [], ],
    2424            'form' => [ 'action' => [], ],
     
    3434            'li'=>[ 'class'=>[], 'style'=>[], ],
    3535            'h3'=>[ ],
    36             'h4'=>[ ],
     36            'h4'=>[ 'class' => [], ],
    3737            'b'=>[ ],
    3838            'hr'=>[ ],
  • catapultodelivery/trunk/readme.txt

    r3420063 r3444321  
    55Requires at least: 5.9
    66Tested up to: 6.8
    7 Stable tag: 1.0.0
     7Stable tag: 1.0.1
    88Requires PHP: 7.4
    99License: GPLv2 or later
     
    2323* Отображение нескольких вариантов (тарифов) доставки в каждой службе доставки;
    2424* Возможность указать желаемую дату получения заказа;
    25 * И многое многое другое. Подробнее можно посмотреть на официальном сайте Catapulto (https://catapulto.ru/modul-dostavki-dlya-internet-magazinov/).
     25* И многое многое другое. Подробнее можно посмотреть на официальном сайте Catapulto (https://catapulto.ru).
    2626
    2727Ознакомьтесь со всеми возможностями модуля в настройках.
    2828
    29 ***Внимание!*** Для работы этого платежного модуля необходимо заключить договор с Catapulto, а также выпустить бесплатный ключ сервиса Dadata.
     29***Внимание!*** Для работы этого платежного модуля необходимо заключить договор с Catapulto а также выпустить бесплатный ключ сервиса Dadata.
    3030
    3131== External services ==
    3232
    33 Этот плагин подключается в API службы доставки Catapulto (https://eshop.catapulto.ru/) для расчета возможных вариантов доставки. Для этого передается информация о составе заказа и местоположении пользователя. Без этой информации рассчитать доставку невозможно. 
     33Этот плагин подключается в API службы доставки Catapulto (https://eshop.catapulto.ru/) для расчета возможных вариантов доставки. Для этого передается информация о составе заказа и местоположении пользователя. Без этой информации рассчитать доставку невозможно.
    3434Сервис предоставляется на основе публичной оферты (https://catapulto.ru/media/public_offer/public_offer.pdf) и политики обработки персональных данных (https://catapulto.ru/privacy/). Используя этот модуль Вы принимаете условия, указанные в этих документах.
    3535Также для более точного определения адреса используется сервис Dadata (https://suggestions.dadata.ru/) в том числе в виде подсказок адреса при вводе. Сервис предоставляется на основе политики конфиденциальности (https://dadata.ru/privacy/) и прочих документов (https://dadata.ru/offer/).
     
    4141== Installation ==
    4242
    43 1. Установите модуль со страницы в каталоге плагинов WordPress (https://wordpress.org/plugins/catapultodelivery/).
    44 1. Активируйте плагин на странице «Плагины» WordPress.
    45 1. Перейдите на страницу «WooCommerce / Настройки / Доставка», нажмите ссылку в главной меню «Курьером или в пункт выдачи» и произведите настройку плагина.
     431. Свяжитесь с Catapulto и получите архив с модулем, распакуйте его.
     441. Его содержимое скопируйте в директорию /wp-content/plugins/catapultodelivery/ Вашего сайта
     451. Активируйте плагин на странице "Плагины" WordPress
     461. Перейдите на страницу "WooCommerce / Настройки / Доставка, нажмите ссылку в главной меню "Курьером или в пункт выдачи" и произведите настройку плагина.
    46471. Активируйте ключ доступа, установите остальные настройки при помощи консультации с менеджером Catapulto.
    4748
     
    5253== Frequently Asked Questions ==
    5354
    54 По всем возникающим вопросам обращайтесь в Catapulto по электронной почте im@catapulto.ru или по номеру телефона 8-800-555-22-41.
     55По всем возникающим вопросам обращайтесь в Catapulto (support@catapulto.ru).
    5556
    5657== Screenshots ==
  • catapultodelivery/trunk/templates/admin/orderPanel.tpl

    r3417476 r3444321  
     1<div class="ctpt_cargowinbg"></div>
     2<div class="ctpt_cargowin">
     3    <div class="ctpt_cargowin_close"></div>
     4    <div class="ctpt_cargowin_content">
     5
     6        <div class="ctpt_alert ctpt_danger rate_update_errors"></div>
     7        <div class="ctpt_alert ctpt_success rate_update_success">
     8            Данные грузомест и габариты успешно сохранены для этого заказа.<br/><br/>
     9            Текущий результат расчета был удален. Необходимо заново выбрать новый расчет доставки.<br/><br/>
     10        </div>
     11        <div class="ctpt_alert ctpt_default">
     12            Внимание! В случае сохранения необходимо будет повторно выбрать вариант доставки.<br/>
     13            До выбора нового варианта доставки отправление заявки в Catapulto невозможно.
     14        </div>
     15
     16        <div class="ctpt_move_win">
     17            <div class="close"></div>
     18            <p>Выберите место <br/>и количество <br/>перемещаемого <br/>в него товара</p>
     19            <select class="form-select">
     20
     21            </select>
     22            <div class="place">
     23                <p>10 /</p>
     24                <input type="text">
     25            </div>
     26            <div class="ctpt_btn ctpt_btn_green">Переместить</div>
     27        </div>
     28
     29        <div class="ctpt_cargo_table">
     30            <h3>Управление грузоместами и товарами</h3>
     31
     32            <div class="cargoes"></div>
     33
     34            <div class="ctpt_btn add_new_cargo">Добавить место</div>
     35
     36            <div class="btm_buttons">
     37                <div class="ctpt_btn ctpt_btn_green ctpt_gdsdata_save">Сохранить</div>
     38                <div class="ctpt_btn ctpt_btn_yellow ctpt_gdsdata_reset">Сбросить</div>
     39            </div>
     40        </div>
     41
     42    </div>
     43</div>
     44
     45<style>
     46    .ctpt_cargowin,
     47    .ctpt_cargowinbg {
     48        position: fixed;
     49        left: 0;
     50        top: 0;
     51        width: 100%;
     52        height: 100%;
     53        display: none;
     54    }
     55    .ctpt_cargowinbg {
     56        background: #fff;
     57        z-index: 10000;
     58        opacity: 0.8;
     59    }
     60    .ctpt_cargowinbg.sh {
     61        display: block;
     62    }
     63    .ctpt_cargowin {
     64        z-index: 10001;
     65        justify-content: center;
     66        overflow-y: scroll;
     67    }
     68    .ctpt_cargowin.sh {
     69        display: flex;
     70    }
     71
     72    .ctpt_btn {
     73        display: inline-block;
     74        padding: 0.375rem 0.75rem;
     75        color: #fff;
     76        text-align: center;
     77        text-decoration: none;
     78        vertical-align: middle;
     79        cursor: pointer;
     80        -webkit-user-select: none;
     81        -moz-user-select: none;
     82        user-select: none;
     83        border: 1px solid #0d6efd;
     84        border-radius: 4px;
     85        background-color: #0d6efd;
     86        transition: color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;
     87    }
     88
     89    .ctpt_btn.ctpt_btn_green {
     90        border-color: #198754;
     91        background-color: #198754;
     92    }
     93    .ctpt_btn.ctpt_btn_yellow {
     94        color: #000;
     95        border-color: #ffc107;
     96        background-color: #ffc107;
     97    }
     98
     99    .ctpt_calc_cargo_gabs {
     100        margin-bottom: 10px;
     101    }
     102
     103    .ctpt_alert {
     104        position: relative;
     105        padding: 20px;
     106        margin-bottom: 20px;
     107        color: #664d03;
     108        background-color: #fff3cd;
     109        border: 1px solid #ffe69c;
     110        border-radius: 0.375rem;
     111
     112        font-size: 13px;
     113    }
     114    .ctpt_alert.ctpt_success {
     115        background-color: #d1e7dd;
     116        border-color: #a3cfbb;
     117        color:#0a3622;
     118    }
     119    .ctpt_alert.ctpt_danger {
     120        background-color: #f8d7da;
     121        border-color: #f1aeb5;
     122        color: #58151c;
     123    }
     124    .ctpt_alert.ctpt_default {
     125        margin-top: 100px;
     126    }
     127
     128    #ctpt_cargoes {
     129        margin-top: 20px;
     130    }
     131
     132</style>
     133
    1134<div class="ctpt_order_panel">
    2135    <h3>Создать отправление</h3>
    3136
    4     <h4>Габариты заказа</h4>
    5     <p><b>Размеры (мм)</b></p>
    6     <p>#len# x #wid# x #hei#</p>
    7     <p><b>Вес (г)</b></p>
    8     <p>#wei#</p>
     137    <h4 class="cargo_gabs_block">Габариты грузомест</h4>
     138    <div class="cargo_gabs_block_content">
     139    </div>
    9140
    10141    <hr>
     
    14145    <p><b>Город отправителя</b></p>
    15146    <p>#senderCity#</p>
     147    <div class="ctpt_tbl" style="padding: 10px 0;">
     148        <p style="float:left;cursor:pointer"><b><label for="ctpt_is_custom_wh">Выбрать другой склад</label></b></p>
     149        <input id="ctpt_is_custom_wh" type="checkbox" name="ctpt_is_custom_wh" checked style="float:left;margin-top:5px;margin-left: 10px" />
     150    </div>
     151    <p><b>Склад отправителя</b></p>
     152    <select id="ctpt_adm_selected_wh" style="width:98%;"></select>
    16153
    17154    <hr/>
     
    72209            <input id="ctpt_needInsurance" type="checkbox" name="ctpt_needInsurance" style="float:left;margin-top:5px;margin-left: 10px" />
    73210        </div>
    74 
    75         <p><b>Страховая стоимость</b></p>
     211        <div class="ctpt_tbl" style="padding: 0 0 10px 0">
     212            <p style="float:left;cursor:pointer"><b><label for="ctpt_is_fitting">Примерка</label></b></p>
     213            <input id="ctpt_is_fitting" type="checkbox" name="ctpt_is_fitting" style="float:left;margin-top:5px;margin-left: 10px" />
     214        </div>
     215        <div class="ctpt_tbl" style="padding: 0 0 10px 0">
     216            <p style="float:left;cursor:pointer"><b><label for="ctpt_is_pr">Частичный выкуп</label></b></p>
     217            <input id="ctpt_is_pr" type="checkbox" name="ctpt_is_pr" style="float:left;margin-top:5px;margin-left: 10px" />
     218        </div>
     219
     220        <div class="ctpt_hint_block">
     221            <span class="ctpt_hintlbl"></span>
     222            <div class="ctpt_hint_content">
     223                <p class="ctpt_hint_content">В случае утраты груза возмещение возможно в размере объявленной ценности, но не больше действительной документально подтвержденной стоимости груза. Также для возмещения будет необходимо предоставить документы, подтверждающие стоимость и основание законного владения грузом.</p>
     224            </div>
     225            <p><b>Объявленная ценность</b></p>
     226        </div>
    76227        <input type="text" id="ctpt_insuranceValue" name="ctpt_insuranceValue" value="#goodsPrice#" />
    77228
     
    94245        </div>
    95246
     247        <p class="ctpt_custom_cargo_valid" style="color: #f00; margin-bottom: 15px">Обнаружено несовпадение корзины заказа и состава грузомест. Необходимо удалить грузоместа, составить их заново и выбрать новый расчет доставки.</p>
     248
    96249        <div class="ctpt_buttons">
    97250            <button id="ctpt_sendorder" class="button button-primary">Отправить</button>
    98251        </div>
    99252    </div>
     253
     254    <button id="ctpt_cargoes" class="button button-primary">Управление грузоместами</button>
     255    <button id="ctpt_cargoer_del" class="button button-primary" style="margin-bottom: 20px;">Очистить грузоместа</button>
     256
    100257</div>
    101258
     
    109266        goodsPrice: #goodsPrice#,
    110267        shippingPrice: #shippingPrice#,
     268        ratePrice: #deliveryPrice#,
    111269        isCod: #isCod#,
    112270        codAmount: #codAmount#,
    113271        isEnsurance: #isInsurance#,
     272        cargoData: #customCargo#,
     273        basePrce: #basePrice#,
     274        isFitting: #isFitting#,
     275        isPR: #isPR#,
     276        isProductSingle: #isProdSingle#,
     277        services: '#ctpt_services#',
     278        std_wei: '#wei#',
     279        std_len: '#len#',
     280        std_wid: '#wid#',
     281        std_hei: '#hei#',
     282        cargo_valid: #customCargoValid#,
     283        w_geo_data_empty_message: '#w_geo_data_empty_message#',
     284        w_ws_api_domain: '#w_ws_api_domain#',
     285        insurance_cost: '#insuranceConfig#',
     286        warehouses: #warehouses#,
     287        selectedwh: #selectedwh#,
    114288    };
     289    window.ctptData.insurance_cost = Number(window.ctptData.insurance_cost);
     290    if (isNaN(window.ctptData.insurance_cost)) window.ctptData.insurance_cost = 0;
    115291
    116292    if (isEmpty) {
    117293        document.querySelector('.ctpt_datablock').style.display = 'none';
    118294        document.querySelector('.ctpt_warnempty').style.display = 'block';
     295    }
     296
     297    document.querySelector('#ctpt_is_custom_wh').checked = false;
     298    for (let i in window.ctptData.warehouses) {
     299        const el = document.createElement('option');
     300        el.setAttribute('value', window.ctptData.warehouses[i].id);
     301        if (window.ctptData.warehouses[i].id == window.ctptData.selectedwh)
     302            el.setAttribute('selected','selected');
     303        el.innerHTML = '(' + window.ctptData.warehouses[i].id + ') ' + window.ctptData.warehouses[i].whname;
     304        document.querySelector('#ctpt_adm_selected_wh').appendChild(el);
     305    }
     306    document.getElementById('ctpt_adm_selected_wh').setAttribute('disabled','disabled');
     307    document.getElementById('ctpt_is_custom_wh').onchange = function(e) {
     308        if (e.target.checked) {
     309            document.getElementById('ctpt_adm_selected_wh').removeAttribute('disabled');
     310        } else {
     311            document.getElementById('ctpt_adm_selected_wh').setAttribute('disabled','disabled');
     312        }
    119313    }
    120314
     
    127321            cityFrom: '#senderCity#',
    128322        },
     323        isMultiWarehouse: true,
    129324        startTabMap: #widgetMapMode#,
    130325        dadata_token: '#dadataToken#',
    131             cargo: {
    132             height: #hei#,
    133             length: #len#,
    134             quantity: 1,
    135             width: #wid#,
    136             weight: #wei#,
    137             cargo_comment:'#cargoComment#',
    138         },
    139326        services_filter: '#serviceFilter#',
    140327        filter_card: #isCard#,
     
    146333        delivery_type: '#widgetDeliveryFrom#',
    147334        day_shift: #day_shift#,
    148         inverse_delivery_type_for_operators: #inverseOperators#,
    149335
    150336        need_insurance: #needInsurance#,
    151337        insured_value: 0,
     338        warehouseId: 0,
    152339    };
    153340
Note: See TracChangeset for help on using the changeset viewer.