Files
Mohamed Youssef 94608c02a0
Build OpenCart Extension / build-release (push) Successful in 4m1s
init
2026-07-31 17:26:38 +03:00

247 lines
8.0 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<modification>
<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>
<add position=""><![CDATA[]]></add>
</operation>
</file>
</modification>