-
Notifications
You must be signed in to change notification settings - Fork 27
/
Copy pathongkir-zone.php
184 lines (151 loc) · 5.4 KB
/
ongkir-zone.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
<?php
if (!defined('ABSPATH')) { exit; }
require_once ONGKIR_DIR . '/includes/rajaongkir.php';
require_once ONGKIR_DIR . '/includes/ongkir-data.php';
if (!class_exists('Ongkir_Zone')):
/**
* Zone setting for Indo Shipping
*/
class Ongkir_Zone extends WC_Shipping_Method {
private $api;
private $main_settings;
public function __construct($instance_id = 0) {
$this->id = 'ongkir_zone';
$this->instance_id = absint($instance_id);
$this->title = __('Ongkir Indonesia');
$this->method_title = __('Ongkir Indonesia');
$this->method_description = __('Indonesian domestic shipping with JNE, TIKI, Ninja Xpress, Sicepat, or POS');
$this->supports = ['shipping-zones', 'instance-settings'];
// global
$this->main_settings = get_option('woocommerce_ongkir_settings');
$this->api = new RajaOngkir($this->main_settings['key']);
// allow save setting
add_action('woocommerce_update_options_shipping_' . $this->id, [$this, 'process_admin_options']);
}
/**
* Calculate_shipping function.
*
* @param mixed $package
*/
function calculate_shipping($package = []) {
// if district not exists or empty
$id_exists = array_key_exists('destination_id', $package['destination']);
if (!$id_exists || empty($package['destination']['destination_id'])) {
return false;
}
$costs = $this->_get_costs($package);
$this->_set_rate($costs);
}
/////
/**
* Get the costs from selected Couriers.
*
* @param array $package - The shipping detail
* @return array - List of cost grouped by each courier
*/
private function _get_costs($package) {
$weight = $this->_calculate_weight($package);
$selected_couriers = $this->_get_selected_couriers();
$args = [
'origin' => $this->main_settings['city'],
'originType' => 'city',
'destination' => $package['destination']['destination_id'],
'destinationType' => 'subdistrict',
'weight' => $weight,
'courier' => $selected_couriers
];
// get the cost
$costs = $this->api->get_costs($args);
return $costs;
}
/**
* Set the Rate based on Cost list from API
*
* @param array $costs - Cost list from API
*/
private function _set_rate($costs) {
if (!$costs) { return; }
// format the costs from API to WooCommerce
foreach ($costs as $courier):
if (empty($courier)) { break; }
// get full list of services
$code = $courier['code'];
if ($code === 'J&T') { $code = 'jnt'; } // for weird reason, the response code for 'jnt' is 'J&T'
$all_services = Ongkir_Data::get_services($code);
// get allowed service from this courier
$setting_id = $code . '_services';
$allowed_services = isset($this->main_settings[$setting_id]) ? $this->main_settings[$setting_id] : array();
foreach ($courier['costs'] as $service):
// check if this service is allowed
$is_allowed = false;
foreach ($allowed_services as $as) {
// if has variation
if (isset($all_services[$as]['vars'])) {
$is_allowed = in_array($service['service'], $all_services[$as]['vars']);
}
else {
$is_allowed = $service['service'] === $as;
}
if ($is_allowed) { break; }
}
if ($is_allowed) {
$rate = array(
'id' => $code . '_' . strtolower($service['service']) . $this->instance_id,
'label' => strtoupper($code) . ' ' . $service['service'],
'cost' => $service['cost'][0]['value'],
'calc_tax' => 'per_order'
);
$this->add_rate($rate);
}
endforeach;
endforeach;
}
/**
* Calculate the weight of items in cart. If all items has no weight specified, it will return 1.
*
* @param array $package - POST parameter
* @return int - THe weight in the unit specified in admin.
*/
private function _calculate_weight($package) {
global $woocommerce;
$weight = wc_get_weight($woocommerce->cart->cart_contents_weight, 'g');
// calculate volume
// @warn - Setting default to "1" can cause item to be much larger if unit is set to "inch"
$volume = array_reduce($woocommerce->cart->get_cart_contents(), function($result, $item) {
$product = $item['data'];
$length = (int) $product->get_length() ?? 1;
$width = (int) $product->get_width() ?? 1;
$height = (int) $product->get_height() ?? 1;
$result += $length * $width * $height;
return $result;
}, 0);
$volume = wc_get_dimension($volume, 'cm');
$weight_volume = $volume / 6; //@todo: make this formula into a setting
// if volume is heavier than weight, use the volume
$weight = $weight_volume > $weight ? $weight_volume : $weight;
if ($weight > 0) {
return $weight;
}
// if no weight data, return default weight or 1kg
else {
$weight = (int) ceil(apply_filters('ongkir_default_weight', 1000));
return $weight;
}
}
/**
* Get selected services from the courier
*
* @return string - The courier format accepted by RajaOngkir, separated by semicolon (jne:tiki:pos)
*/
private function _get_selected_couriers() {
$couriers = Ongkir_Data::get_couriers();
$selected_couriers = [];
foreach ($couriers as $id => $name) {
if (!empty($this->main_settings[$id . '_services'])) {
$selected_couriers[] = $id;
}
}
return join(':', $selected_couriers);
}
}
endif;