/** * Apply sub total discount. */ function apply_sub_total($cart, $sub_total, $discounts) { foreach ((array) $discounts as $discount) { foreach ((array) $discount['rules'] as $rule) { if ($rule['enabled'] !== null && !$rule['enabled']) { continue; } switch ($rule['type']) { case 'product': foreach ((array) $cart['items'] as $item) { if ($item['id'] != $rule['product_id']) { continue; } $d_qty = $discount_qty[$item['id']]; // Limit discount quantity? if ($rule['quantity']) { $qty = $rule['quantity'] > $item['quantity'] ? $item['quantity'] : $rule['quantity']; if ($d_qty + $qty >= $rule['quantity']) { $qty = $qty - ($discout_qty + $qty - $rule['quantity']); } } else { $qty = $item['quantity']; } // Subtract item from total. $sub_total -= $item['price'] * $qty; // Apply discount value to price. $item_price = self::apply_value($item['price'], $rule['value']); // Add new item price back to total. $sub_total += $item_price * $qty; // Track total qty discounted. $discount_qty[$item['id']] += $qty; } break; case 'category': foreach ((array) $cart['items'] as $item) { if (in_array($rule['category_id'], (array) $item['category_ids'])) { $d_qty = $discount_qty[$item['id']]; // Limit discount quantity? if ($rule['quantity']) { $qty = $rule['quantity'] > $item['quantity'] ? $item['quantity'] : $rule['quantity']; if ($d_qty + $qty > $rule['quantity']) { $qty = $qty - ($discout_qty + $qty - $rule['quantity']); } } else { $qty = $item['quantity']; } // Subtract item from total. $sub_total -= $item['price'] * $qty; // Apply discount value to price. $item_price = self::apply_value($item['price'], $rule['value']); // Add new item price back to total. $sub_total += $item_price * $qty; // Track total qty discounted. $discount_qty[$item['id']] += $qty; $items_discounted++; } // Break if reached category limit. if ($rule['limit'] && $items_discounted >= $rule['limit']) { break; } } break; case '': case 'total': $sub_total = Discounts::apply_value($sub_total, $rule['value']); break; } } } return $sub_total; }
/** * Get UPS rate quotes. */ function fwd_ups_rates($params, $settings) { // Configurable UPS service methods. $service_list = array('01' => 'UPS Next Day Air', '02' => 'UPS Second Day Air', '03' => 'UPS Ground', '11' => 'UPS Standard', '12' => 'UPS Three-Day Select', '13' => 'UPS Next Day Air Saver', '65' => 'UPS Worldwide Saver', '07' => 'UPS Worldwide Express', '08' => 'UPS Worldwide Expedited', '14' => 'UPS Next Day Air Early A.M.', '54' => 'UPS Worldwide Express Plus', '59' => 'UPS Second Day Air A.M.'); // If params are empty, return available methods only. if (empty($params)) { $methods = array(); foreach ((array) $settings['methods'] as $key => $method) { if ($method) { $method = is_array($method) ? $method : array(); $methods[] = array('id' => $key, 'name' => $method['name'] ?: $service_list[$key]); } } return $methods; } // Get shipper, default or specific settings. $shipper = array_merge(array('package_weight' => 100), (array) $settings['shippers'][0], (array) $settings['shippers'][$params['shipper']]); // Split package by weight limit? if ($shipper['package_weight'] && $params['weight'] > $shipper['package_weight']) { $num_packages = ceil($params['weight'] / $shipper['package_weight']); for ($i = 0; $i < $num_packages; $i++) { if ($i >= 200) { break; } $params['packages'][$i] = array('weight' => $params['weight'] / $num_packages, 'units' => $params['units']); } } else { $params['packages'][1] = array('weight' => $params['weight'] ?: 1, 'units' => $params['units']); } // Add package(s) to request. foreach ($params['packages'] as $package) { // Dimensions? if ($package['dimensions']) { $package_dimensions = "\n\t\t\t\t<Dimensions>\n\t\t\t\t\t<Length>{$package['dimensions']['length']}</Length>\n\t\t\t\t\t<Width>{$package['dimensions']['width']}</Width>\n\t\t\t\t\t<Height>{$package['dimensions']['height']}</Height>\n\t\t\t\t\t<UnitOfMeasurement>\n\t\t\t\t\t\t<Code>" . ($package['dimensions']['units'] ?: 'IN') . "</Code>\n\t\t\t\t\t</UnitOfMeasurement>\n\t\t\t\t</Dimensions>\n\t\t\t"; } else { $package_dimensions = null; } $request_packages .= "\n\t\t\t<Package>\n\t\t\t\t<PackagingType>\n\t\t\t\t\t<Code>02</Code>\n\t\t\t\t</PackagingType>\n\t\t\t\t<PackageWeight>\n\t\t\t\t\t<UnitOfMeasurement>\n\t\t\t\t\t\t<Code>" . ($package['units'] ? "{$package['units']}S" : 'LBS') . "</Code>\n\t\t\t\t\t</UnitOfMeasurement>\n\t\t\t\t\t<Weight>{$package['weight']}</Weight>\n\t\t\t\t</PackageWeight>\n\t\t\t\t{$package_dimensions}\n\t\t\t</Package>\n\t\t"; } // XML API call. $request = "\n\t\t<?xml version=\"1.0\" ?>\n\t\t<AccessRequest xml:lang='en-US'>\n\t\t\t<AccessLicenseNumber>{$settings['license']}</AccessLicenseNumber>\n\t\t\t<UserId>{$settings['login']}</UserId>\n\t\t\t<Password>{$settings['password']}</Password>\n\t\t</AccessRequest>\n\t\t<?xml version=\"1.0\" ?>\n\t\t<RatingServiceSelectionRequest>\n\t\t\t<Request>\n\t\t\t\t<RequestAction>Rate</RequestAction>\n\t\t\t\t<RequestOption>Shop</RequestOption>\n\t\t\t</Request>\n\t\t\t<PickupType>\n\t\t\t\t<Code>01</Code>\n\t\t\t</PickupType>\n\n\t\t\t<Shipment>\n\t\t\t\t<Shipper>\n\t\t\t\t\t<ShipperNumber>" . ($shipper['account'] ?: $settings['account']) . "</ShipperNumber>\n\t\t\t\t\t<Address>\n\t\t\t\t\t\t<City>{$shipper['city']}</City>\n\t\t\t\t\t\t<PostalCode>{$shipper['zip']}</PostalCode>\n\t\t\t\t\t\t<CountryCode>" . ($shipper['country'] ?: 'US') . "</CountryCode>\n\t\t\t\t\t</Address>\n\t\t\t\t</Shipper>\n\n\t\t\t\t<ShipTo>\n\t\t\t\t\t<Address>\n\t\t\t\t\t\t<City>{$params['city']}</City>\n\t\t\t\t\t\t<StateProvinceCode>{$params['state']}</StateProvinceCode>\n\t\t\t\t\t\t<PostalCode>{$params['zip']}</PostalCode>\n\t\t\t\t\t\t<CountryCode>" . ($params['country'] ?: 'US') . "</CountryCode>\n\t\t\t\t\t\t<ResidentialAddressIndicator/>\n\t\t\t\t\t</Address>\n\t\t\t\t</ShipTo>\n\n\t\t\t\t{$request_packages}\n\n\t\t\t</Shipment>\n\n\t\t</RatingServiceSelectionRequest>\n\t"; // Initialize connection with UPS service. $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $settings['host'] ?: "https://wwwcie.ups.com/ups.app/xml/Rate"); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $request); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); $response = curl_exec($ch); curl_close($ch); if ($response) { $doc = new SimpleXMLElement($response); $response_code = (string) $doc->Response[0]->ResponseStatusCode; } switch ($response_code) { // Good response. case 1: foreach ($doc->RatedShipment as $shipment) { if ($service_type = (string) $shipment->Service[0]->Code) { $price = (double) $shipment->TotalCharges[0]->MonetaryValue; // Markup? if ($settings['markup']) { $price = Discounts::apply_value($price, '+' . $settings['markup']); } // Discount? if ($settings['discount']) { $price = Discounts::apply_value($price, $settings['markup']); } // Rated method configured/available? if ($method = $settings['methods'][$service_type]) { $method = is_array($method) ? $method : array(); $service_name = $method['name'] ?: $service_list[$service_type]; $service_price = round($price, 2); $shipment_rates[] = array('id' => $service_type, 'name' => $service_name, 'price' => $service_price); } } } break; // Bad response. // Bad response. case 0: throw new Exception((string) $doc->Response[0]->Error[0]->ErrorDescription[0]); break; // No response? // No response? default: throw new Exception("Unknown response from UPS Rating Service"); } return $shipment_rates; }
/** * Get FedEx rate quotes. */ function fwd_fedex_rates($params, $settings) { // Configurable FedEx service methods. $service_list = array('FEDEX_GROUND' => 'Fedex Ground', 'FEDEX_EXPRESS_SAVER' => 'Fedex Express Saver', 'FEDEX_2_DAY' => 'Fedex 2-Day Air', 'FEDEX_2_DAY_AM' => 'Fedex 2-Day Air A.M.', 'STANDARD_OVERNIGHT' => 'Fedex Standard Overnight', 'PRIORITY_OVERNIGHT' => 'Fedex Priority Overnight', 'FIRST_OVERNIGHT' => 'Fedex First Overnight', 'INTERNATIONAL_PRIORITY' => 'Fedex Priority International'); // If params are empty, return available methods only. if (empty($params)) { $methods = array(); foreach ((array) $settings['methods'] as $key => $method) { if ($method) { $method = is_array($method) ? $method : array(); $methods[] = array('id' => $key, 'name' => $method['name'] ?: $service_list[$key]); } } return $methods; } // Get shipper, default or specific. $shipper = array_merge(array('package_weight' => 100), (array) $settings['shippers'][0], (array) $settings['shippers'][$params['shipper']]); // Disable WSDL caching. ini_set('soap.wsdl_cache_enabled', '0'); // Create SOAP client with Fedex RateService WSDL. $client = new SoapClient(dirname(__FILE__) . '/wsdl/RateService_v10.wsdl', array('trace' => 1)); // Set endpoint host? if ($settings['host']) { $client->__setLocation($settings['host']); } // Split package by weight limit? if ($shipper['package_weight'] && $params['weight'] > $shipper['package_weight']) { $num_packages = ceil($params['weight'] / $shipper['package_weight']); for ($i = 0; $i < $num_packages; $i++) { if ($i >= 200) { break; } $params['packages'][$i] = array('insurance_amount' => $params['insurance_amount'] / $num_packages, 'insurance_currency' => $params['insurance_currency'], 'weight' => $params['weight'] / $num_packages, 'units' => $params['units']); } } // Setup request. $request = array('WebAuthenticationDetail' => array('UserCredential' => array('Key' => $settings['key'], 'Password' => $settings['password'])), 'ClientDetail' => array('AccountNumber' => $settings['account'], 'MeterNumber' => $settings['meter']), 'TransactionDetail' => array('CustomerTransactionId' => '*** Rate Request v10 using PHP ***'), 'Version' => array('ServiceId' => 'crs', 'Major' => '10', 'Intermediate' => '0', 'Minor' => '0'), 'ReturnTransitAndCommit' => true, 'RequestedShipment' => array('DropoffType' => 'REGULAR_PICKUP', 'ShipTimestamp' => date('c'), 'PackagingType' => 'YOUR_PACKAGING', 'Shipper' => array('Address' => array('StreetLines' => array($shipper['address']), 'City' => $shipper['city'], 'StateOrProvinceCode' => $shipper['state'], 'PostalCode' => $shipper['zip'], 'CountryCode' => $shipper['country'] ?: 'US')), 'Recipient' => array('Address' => array('StreetLines' => array($params['address']), 'City' => $params['city'], 'StateOrProvinceCode' => $params['state'], 'PostalCode' => $params['zip'], 'CountryCode' => $params['country'] ?: 'US')), 'ShippingChargesPayment' => array('PaymentType' => 'SENDER', 'Payor' => array('AccountNumber' => $shipper['account'] ?: $settings['account'], 'CountryCode' => $shipper['country'] ?: 'US')), 'RateRequestTypes' => 'ACCOUNT', 'RateRequestTypes' => 'LIST', 'PackageCount' => $params['packages'] ? count($params['packages']) : '1', 'RequestedPackages' => array())); // Default single package? if (count($params['packages']) == 0) { $params['packages'][0] = array('insurance_amount' => $params['insurance_amount'], 'insurance_currency' => $params['insurance_currency'], 'weight' => $params['weight'] ?: 1, 'units' => $params['units']); if ($params['dimensions']) { $params['packages'][0]['dimensions'] = array('length' => $params['dimensions']['length'], 'width' => $params['dimensions']['width'], 'height' => $params['dimensions']['height'], 'units' => $params['dimensions']['units']); } } // Add package(s) to request. foreach ($params['packages'] as $seq => $package) { $request['RequestedShipment']['RequestedPackageLineItems'][$seq] = array('SequenceNumber' => $seq + 1, 'GroupPackageCount' => 1, 'InsuredValue' => array('Amount' => $package['insurance_amount'] ?: 0, 'Currency' => $package['insurance_currency'] ?: 'USD'), 'Weight' => array('Value' => $package['weight'], 'Units' => $package['units'] ?: 'LB')); // Dimensions? if ($package['dimensions']) { $request['RequestedShipment']['RequestedPackageLineItems'][$seq]['Dimensions'] = array('Length' => $package['dimensions']['length'], 'Width' => $package['dimensions']['width'], 'Height' => $package['dimensions']['height'], 'Units' => $package['dimensions']['units'] ?: 'IN'); } } // Try the request. try { $response = $client->getRates($request); if ($response->HighestSeverity != 'FAILURE' && $response->HighestSeverity != 'ERROR') { if (!is_array($response->RateReplyDetails)) { $response->RateReplyDetails = array($response->RateReplyDetails); } foreach ($response->RateReplyDetails as $RateReplyDetail) { $service_type = $RateReplyDetail->ServiceType; if ($service_list[$service_type]) { $rsd = end($RateReplyDetail->RatedShipmentDetails); $tnc = $rsd->ShipmentRateDetail->TotalNetCharge; $price = (double) preg_replace('/[^\\d\\.]/i', '', $tnc->Amount); // Markup? if ($settings['markup']) { $price = Discounts::apply_value($price, '+' . $settings['markup']); } // Discount? if ($settings['discount']) { $price = Discounts::apply_value($price, $settings['markup']); } // Rated method configured/available? if ($method = $settings['methods'][$service_type]) { $method = is_array($method) ? $method : array(); $service_name = $method['name'] ?: $service_list[$service_type]; $service_price = round($price, 2); $shipment_rates[] = array('id' => $service_type, 'name' => $service_name, 'price' => $service_price); } } } } elseif ($response->HighestSeverity == 'FAILURE' || $response->HighestSeverity == 'ERROR') { throw new Exception($response->Notifications->LocalizedMessage ?: $response->Notifications->Message); } } catch (SoapFault $e) { throw new Exception($e->getMessage()); } return $shipment_rates; }