This commit is contained in:
+233
-2
@@ -1,11 +1,242 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<modification>
|
||||
<name></name>
|
||||
<code></code>
|
||||
<name>Prevent PO Box Addresses</name>
|
||||
<code>mydev_prevent_po_box_addresses</code>
|
||||
<author><![CDATA[<b style="color: green">MY-Dev | </b><b>Mohamed Youssef</b>]]></author>
|
||||
<link>https://my-dev.pro</link>
|
||||
<version>1.0.0</version>
|
||||
|
||||
<file path="catalog/model/account/address.php">
|
||||
<operation error="log">
|
||||
<search><![CDATA[public function getTotalAddresses() {]]></search>
|
||||
<add position="before"><![CDATA[
|
||||
private function getRequest(string $url): ?array
|
||||
{
|
||||
$connection = curl_init();
|
||||
|
||||
curl_setopt_array($connection, [
|
||||
CURLOPT_URL => $url,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_TIMEOUT => 10,
|
||||
CURLOPT_CONNECTTIMEOUT => 5,
|
||||
]);
|
||||
|
||||
$response = curl_exec($connection);
|
||||
|
||||
if ($response === false) {
|
||||
curl_close($connection);
|
||||
return [];
|
||||
}
|
||||
|
||||
$status = curl_getinfo($connection, CURLINFO_HTTP_CODE);
|
||||
curl_close($connection);
|
||||
|
||||
if ($status !== 200) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return json_decode($response, true);
|
||||
}
|
||||
|
||||
// fetch longitude & latitude based on ZIP Code
|
||||
private function getCustomerLocation(string $zipcode, string $countryCode = 'US'): array
|
||||
{
|
||||
$url = sprintf(
|
||||
'https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/findAddressCandidates?SingleLine=%s&f=json&outFields=*&countryCode=%s',
|
||||
urlencode((string)$zipcode),
|
||||
urlencode($countryCode)
|
||||
);
|
||||
|
||||
$response = $this->getRequest($url);
|
||||
if (empty($response['candidates'])) {
|
||||
return [];
|
||||
}
|
||||
return $response['candidates'][0]['location'];
|
||||
}
|
||||
|
||||
private function getAvailableBoxes(string $zipcode, string $countryCode = 'US'): array
|
||||
{
|
||||
$location = $this->getCustomerLocation($zipcode, $countryCode);
|
||||
|
||||
if (empty($location)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$longitude = $location['x'];
|
||||
$latitude = $location['y'];
|
||||
|
||||
$url = sprintf(
|
||||
'https://poboxes.usps.com/pobol/app/poLocations/search?longitude=%s&latitude=%s',
|
||||
$location['x'],
|
||||
$location['y']
|
||||
);
|
||||
|
||||
return $this->getRequest($url);
|
||||
|
||||
}
|
||||
|
||||
private function normalizeAddress(string $address): string
|
||||
{
|
||||
$address = strtoupper(trim($address));
|
||||
|
||||
// Remove punctuation
|
||||
$address = preg_replace('/[.,#]/', ' ', $address);
|
||||
|
||||
// Normalize whitespace
|
||||
$address = preg_replace('/\s+/', ' ', $address);
|
||||
|
||||
$replacements = [
|
||||
// Directions
|
||||
'NORTHWEST' => 'NW',
|
||||
'NORTHEAST' => 'NE',
|
||||
'SOUTHWEST' => 'SW',
|
||||
'SOUTHEAST' => 'SE',
|
||||
'NORTH' => 'N',
|
||||
'SOUTH' => 'S',
|
||||
'EAST' => 'E',
|
||||
'WEST' => 'W',
|
||||
|
||||
// Street suffixes
|
||||
'STREET' => 'ST',
|
||||
'AVENUE' => 'AVE',
|
||||
'ROAD' => 'RD',
|
||||
'DRIVE' => 'DR',
|
||||
'BOULEVARD' => 'BLVD',
|
||||
'LANE' => 'LN',
|
||||
'COURT' => 'CT',
|
||||
'CIRCLE' => 'CIR',
|
||||
'PLACE' => 'PL',
|
||||
'PARKWAY' => 'PKWY',
|
||||
'TERRACE' => 'TER',
|
||||
'HIGHWAY' => 'HWY',
|
||||
'SQUARE' => 'SQ',
|
||||
'TRAIL' => 'TRL',
|
||||
'WAY' => 'WAY',
|
||||
'LOOP' => 'LOOP',
|
||||
'CENTER' => 'CTR',
|
||||
'MOUNT' => 'MT',
|
||||
'JUNCTION' => 'JCT',
|
||||
|
||||
// Common unit designators
|
||||
'APARTMENT' => 'APT',
|
||||
'SUITE' => 'STE',
|
||||
'BUILDING' => 'BLDG',
|
||||
'FLOOR' => 'FL',
|
||||
'ROOM' => 'RM',
|
||||
|
||||
// PO Box
|
||||
'POST OFFICE BOX' => 'PO BOX',
|
||||
'POST OFFICE' => 'PO',
|
||||
];
|
||||
|
||||
foreach ($replacements as $search => $replace) {
|
||||
$address = preg_replace(
|
||||
'/\b' . preg_quote($search, '/') . '\b/',
|
||||
$replace,
|
||||
$address
|
||||
);
|
||||
}
|
||||
|
||||
// Normalize whitespace again
|
||||
$address = preg_replace('/\s+/', ' ', trim($address));
|
||||
|
||||
return $address;
|
||||
}
|
||||
|
||||
public function hasPOBoxFacility(string $zipCode, string $address): bool
|
||||
{
|
||||
|
||||
$status = false;
|
||||
$facilities = $this->getAvailableBoxes((string)$zipCode);
|
||||
|
||||
if (empty($facilities)) {
|
||||
return $status;
|
||||
}
|
||||
|
||||
$searchAddress = $this->normalizeAddress($address);
|
||||
$address_zipcode = explode('-', $zipCode); // Use only the first part of the ZIP code
|
||||
$zipcode = $address_zipcode[0];
|
||||
$zip4code = $address_zipcode[1] ?? null;
|
||||
|
||||
foreach ($facilities as $facility) {
|
||||
if (($facility['address']['zipCode'] ?? '') !== $zipcode ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$facilityAddress = $this->normalizeAddress($facility['address']['addressLine1']);
|
||||
|
||||
if (strpos($searchAddress, $facilityAddress) !== false || strpos($facilityAddress, $searchAddress) !== false) {
|
||||
$status = true;
|
||||
}
|
||||
|
||||
if (($facility['address']['zip4Code'] ?? '') !== $zip4code) {
|
||||
$status = false;
|
||||
}
|
||||
|
||||
if ($status) {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
]]></add>
|
||||
</operation>
|
||||
</file>
|
||||
|
||||
<file path="catalog/controller/checkout/{payment_address,shipping_address}.php">
|
||||
<operation error="log">
|
||||
<search><![CDATA[if ($this->request->post['country_id'] == '') {]]></search>
|
||||
<add position="before"><![CDATA[
|
||||
if ($this->model_account_address->hasPOBoxFacility($this->request->post['postcode'], $this->request->post['address_1'])) {
|
||||
$json['error']['address_1'] = $this->language->get('error_po_box');
|
||||
}
|
||||
]]></add>
|
||||
</operation>
|
||||
</file>
|
||||
|
||||
<file path="catalog/controller/account/address.php">
|
||||
<operation error="log">
|
||||
<search><![CDATA[$country_info = $this->model_localisation_country->getCountry($this->request->post['country_id']);]]></search>
|
||||
<add position="before"><![CDATA[
|
||||
if ($this->model_account_address->hasPOBoxFacility($this->request->post['postcode'], $this->request->post['address_1'])) {
|
||||
$json['error']['address_1'] = $this->language->get('error_po_box');
|
||||
}
|
||||
]]></add>
|
||||
</operation>
|
||||
</file>
|
||||
|
||||
<file path="catalog/controller/checkout/guest.php">
|
||||
<operation error="log">
|
||||
<search><![CDATA[if ($this->request->post['country_id'] == '') {]]></search>
|
||||
<add position="before"><![CDATA[
|
||||
$this->load->model('account/address');
|
||||
if ($this->model_account_address->hasPOBoxFacility($this->request->post['postcode'], $this->request->post['address_1'])) {
|
||||
$json['error']['address_1'] = $this->language->get('error_po_box');
|
||||
}
|
||||
]]></add>
|
||||
</operation>
|
||||
</file>
|
||||
|
||||
<file path="catalog/language/*/checkout/checkout.php">
|
||||
<operation error="skip">
|
||||
<search><![CDATA[$_['error_address_1'] = 'Address 1 must be between 3 and 128 characters!';]]></search>
|
||||
<add position="after"><![CDATA[
|
||||
$_['error_po_box'] = 'PO Box addresses are not allowed.';
|
||||
]]></add>
|
||||
</operation>
|
||||
</file>
|
||||
|
||||
<file path="catalog/language/*/account/address.php">
|
||||
<operation error="skip">
|
||||
<search><![CDATA[$_['error_address_1'] = 'Address must be between 3 and 128 characters!';]]></search>
|
||||
<add position="after"><![CDATA[
|
||||
$_['error_po_box'] = 'PO Box addresses are not allowed.';
|
||||
]]></add>
|
||||
</operation>
|
||||
</file>
|
||||
|
||||
<file path="">
|
||||
<operation error="skip">
|
||||
<search><![CDATA[]]></search>
|
||||
|
||||
Reference in New Issue
Block a user