shacker Posted July 14, 2020 Share Posted July 14, 2020 (edited) En este tutorial veremos paso a paso como añadir el campo ciudad como menú desplegable al crear o modificar una dirección. EL primer paso es crear una tabla con las ciudades. La tabla la llamaremos city, y tendrá esta estructura Los id_state deben ser los da cada estado que tenga su tienda prestashop. La tabla se vería así: El siguiente paso es modificar la tabla ps_address añadiendo un campo id_city Por último, modificaremos la tabla address_format definiendo para que países usaremos el formato de droptown en la ciudad. Solo basta con editar el campo format, que generalmente cuando contiene estados luce asi: Y le cambiaremos el campo city asi city:name. Name añadiría el dropdown: A esta altura la tienda nos dará errores ya que faltaran clases, asi que ahora debemos modificar los archivos para que todo esto funcione. Primero crearemos un archivo City.php en la carpeta clases que permitirá trabajar con las ciudades.El archivo contendrá: class CityCore extends ObjectModel { public $id_city; public $id_state; public $name; protected $fieldsRequired = array('id_city', 'name'); protected $fieldsSize = array('name' => 128, 'id_state' => 10); protected $fieldsValidate = array('name' => 'isGenericName', 'id_state' => 'isUnsignedId', ); protected $table = 'city'; protected $identifier = 'id_city'; private static $_cache_get_cities = array(); public function getFields() { parent::validateFields(); $fields['id_city'] = (int)($this->id_city); $fields['name'] = pSQL($this->name); $fields['id_state'] = pSQL($this->id_state); return $fields; } public function delete() { $id = $this->id; parent::delete(); } public static function getCities($id_state) { $id_city = Db::getInstance()->ExecuteS(' SELECT * FROM `'._DB_PREFIX_.'city` WHERE `id_state` = '.(int)$id_state.' ORDER BY `name`;' ); return $id_city; } public static function getCityName($id_city) { return Db::getInstance()->getValue(' SELECT `name` FROM `'._DB_PREFIX_.'city` WHERE `id_city` = '.(int)$id_city ); } } El siguiente archivo es el clases/form/CustomerAddressFormatter.php Buscaremos esta línea de estados elseif ($entity === 'State') { if ($this->country->contains_states) { $states = State::getStatesByIdCountry($this->country->id, true); foreach ($states as $state) { $formField->addAvailableValue( $state['id_state'], $state[$entityField] ); } $formField->setRequired(true); } } y añadiremos al final elseif ($entity === 'city') { $formField->setType('select'); $formField->setName('id_' . strtolower($entity)); $cities = State::getCities(315); foreach ($cities as $city) { $formField->addAvailableValue( $city['id_city'], $city[$entityField] ); } $formField->setRequired(false); } Luego añadiremos esta función a el archivo clases/State.php public static function getCities($id_state) { $id_city = Db::getInstance()->ExecuteS(' SELECT * FROM `'._DB_PREFIX_.'city` WHERE `id_state` = '.(int)$id_state.' ORDER BY `name`;' ); return $id_city; } Para estos archivos ya creados siempre podemos usar un override para evitar perder cambios al actualizar PrestaShop EL siguiente archivo es el clases/Address.php Añadiremos al inicio las variables publicas: public $id_city; public $cityName; En la fucion public static $definition = array( Añadiremos al final el campo creado id_city para la tabla address 'id_city' => 'isUnsignedId', Y añadiremos esta nueva función public function getFields() { if (isset($this->id)) $sql = 'select * from '. _DB_PREFIX_ . 'city WHERE id_city= ' . $this->id_city; $sql2 = Db::getInstance()->getRow($sql); $fields['id_address'] = (int)($this->id); $fields['id_customer'] = is_null($this->id_customer) ? 0 : (int)($this->id_customer); $fields['id_manufacturer'] = is_null($this->id_manufacturer) ? 0 : (int)($this->id_manufacturer); $fields['id_supplier'] = is_null($this->id_supplier) ? 0 : (int)($this->id_supplier); $fields['id_country'] = (int)($this->id_country); $fields['id_state'] = (int)($this->id_state); $fields['alias'] = pSQL($this->alias); $fields['company'] = pSQL($this->company); $fields['lastname'] = pSQL($this->lastname); $fields['firstname'] = pSQL($this->firstname); $fields['address1'] = pSQL($this->address1); $fields['address2'] = pSQL($this->address2); $fields['postcode'] = pSQL($this->postcode); $fields['city'] = pSQL($sql2['name']); $fields['other'] = pSQL($this->other); $fields['phone'] = pSQL($this->phone); $fields['phone_mobile'] = pSQL($this->phone_mobile); $fields['vat_number'] = pSQL($this->vat_number); $fields['dni'] = pSQL($this->dni); $fields['deleted'] = (int)($this->deleted); $fields['date_add'] = pSQL($this->date_add); $fields['date_upd'] = pSQL($this->date_upd); $fields['id_city'] = is_null($this->id_city) ? 0 : (int)($this->id_city); return $fields; } Y al final modificaremos esta función public static function initialize($id_address = null, $with_geoloc = false) donde este elseif debe añadir el campo city } elseif ($with_geoloc && isset($context->customer->geoloc_id_country)) { $address = new Address(); $address->id_country = (int) $context->customer->geoloc_id_country; $address->id_state = (int) $context->customer->id_state; $address->id_city = (int) $context->customer->id_city; $address->postcode = $context->customer->postcode; } Luego el classes/form/customeraddressform.php reemplazaremos esta función public function submit() { if (!$this->validate()) { return false; } $address = new Address( $this->getValue('id_address'), $this->language->id ); foreach ($this->formFields as $formField) { if ($formField->getName() == 'id_city'){ $id_city = Db::getInstance()->getRow(' SELECT * FROM `'._DB_PREFIX_.'city` WHERE `id_city` = '.$formField->getValue().';'); $address->city = $id_city['name']; $address->{$formField->getName()} = $formField->getValue(); } else { $address->{$formField->getName()} = $formField->getValue(); } } if (!isset($this->formFields['id_state'])) { $address->id_state = 0; } if (empty($address->alias)) { $address->alias = $this->translator->trans('My Address', [], 'Shop.Theme.Checkout'); } Hook::exec('actionSubmitCustomerAddressForm', array('address' => &$address)); $this->setAddress($address); $this->getPersister()->save( $address, $this->getValue('token')); Db::getInstance()->Execute('UPDATE `'._DB_PREFIX_.'address` SET `city` = \''.$address->city.'\' WHERE id_address = '.$address->id); return true; } El siguiente paso es añadir el código javascript para que tome las ciudades al cambiar de estado: Para esto modificaremos el archivo themes/nuestrotheme/templates/_partials/javascript.tpl de nuestro theme y le añadiremos este código al final: <!-- direcciones --> {literal} <script> (function(){"use strict";var c=[],f={},a,e,d,b;if(!window.jQuery){a=function(g){c.push(g)};f.ready=function(g){a(g)};e=window.jQuery=window.$=function(g){if(typeof g=="function"){a(g)}return f};window.checkJQ=function(){if(!d()){b=setTimeout(checkJQ,100)}};b=setTimeout(checkJQ,100);d=function(){if(window.jQuery!==e){clearTimeout(b);var g=c.shift();while(g){jQuery(g);g=c.shift()}b=f=a=e=d=window.checkJQ=null;return true}return false}}})(); </script> {/literal} {if $page.page_name == "address" or $page.page_name == "order" or $page.page_name == "checkout"} <script type="text/javascript"> $(document).ready(function(){ $(".form-control-select .js-city").last().val(); var mi_ajaxurl = '{$urls.base_url}modules/'; var aux_id_state = {if isset($smarty.post.id_state) and $smarty.post.id_state <> null}{$smarty.post.id_state}{else}{if isset($customer.addresses[$smarty.get.id_address].id_state)}{$customer.addresses[$smarty.get.id_address].id_state}{else}0{/if}{/if}; var aux_id_city = {if isset($smarty.post.id_city) and $smarty.post.id_city <> null}{$smarty.post.id_city}{else}{if isset($customer.addresses[$smarty.get.id_address].id_city)}{$customer.addresses[$smarty.get.id_address].id_city}{else}0{/if}{/if}; var aux_city = '{if isset($smarty.post.city) and $smarty.post.city <> null}{$smarty.post.city}{else}{if isset($customer.addresses[$smarty.get.id_address].city)}{$customer.addresses[$smarty.get.id_address].city}{else}0{/if}{/if}'; {literal} $(document).ready(function(){ $.urlParam = function(name){ var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href); if (results==null) { return null; } return decodeURI(results[1]) || 0; } ajaxCity(); $("[name='id_state']").change(function() { ajaxCity(); }); $("[name='id_city']").change(function() { }); function ajaxCity(valueaaa){ $.ajax({ type: "GET", url: mi_ajaxurl+"ajax_addresses/ajax.php?ajaxCity=1&id_state="+$("[name='id_state']").val()+"&aux_id_state="+aux_id_state+"&aux_city="+aux_city, success: function(r){ if( r == 'false' ){ $("[name='id_city']").fadeOut(); $("[name='id_city'] option[value=0]").attr("selected", "selected"); }else{ $("[name='id_city']").html(r); $("[name='id_city']").fadeIn(); //$('#id_city option[value=0]').attr("selected", "selected"); $("[name='id_city'] option[value='+aux_id_city+']").attr("selected", "selected"); } $("[name='id_city']").trigger('click'); //$("#id_street").trigger('click'); /*/***ajaxStreet();*/ } }); }; }); {/literal} </script> {/if} Por ultimo, crearemos un pseudo modulo para las funciones Ajax. Esto se puede hacer de otras formas, esta es solo una sencilla.En la carpeta modules, creamos una carpeta llamada ajax_addresses y dentro de la misma un archivo llamado ajax.php con este contenido: <?php include(dirname(__FILE__). '/../../config/config.inc.php'); include(dirname(__FILE__). '/../../init.php'); // obtengo city if (isset($_GET['ajaxCity']) AND isset($_GET['id_state'])) { $idTemp = ( (int)(Tools::getValue('id_state')) == 0 ? (int)(Tools::getValue('aux_id_state')) : (int)(Tools::getValue('id_state')) ); $idcity = Tools::getValue('aux_city'); $states = Db::getInstance()->ExecuteS(' SELECT C.id_city, C.name FROM '._DB_PREFIX_.'city C WHERE C.id_state = '.$idTemp.' ORDER BY C.`name` ASC'); $states2 = Db::getInstance()->getRow(' SELECT C.id_city, C.name FROM '._DB_PREFIX_.'city C WHERE C.name = \''.$idcity.'\' ORDER BY C.`name` ASC'); if (is_array($states) AND !empty($states)) { $list = ''; if (Tools::getValue('no_empty') != true) if($idcity != null){ $list = '<option value="'.$states2['name'].'" class="showme" >'.($idcity == 0 ? "---" : $idcity) .'</option>'."\n"; } foreach ($states AS $state) if($idcity == 0){ $list .= '<option value="'.(int)($state['id_city']).'"'.((isset($_GET['id_city']) AND $_GET['id_city'] == $state['id_city']) ? ' selected="selected"' : '').'>'.$state['name'].'</option>'."\n"; } else{ $list .= '<option value="'.(int)($state['id_city']).'"'.((isset($idcity) AND $idcity == $state['name']) ? ' selected="selected"' : '').'>'.$state['name'].'</option>'."\n"; } } else $list = 'false'; die($list); } Luego solo debemos limpiar cache y ya deberíamos ver las ciudades como dropdown. Link a los archivos https://github.com/shacker2/citiesasdropdownprestashop/tree/main Edited September 26, 2021 by shacker (see edit history) 1 3 Link to comment Share on other sites More sharing options...
luishuaymana Posted July 15, 2020 Share Posted July 15, 2020 Un gran tutorial. Excelente Si me doy un tiempo lo modulare. 1 Link to comment Share on other sites More sharing options...
shacker Posted July 15, 2020 Author Share Posted July 15, 2020 gracias! Link to comment Share on other sites More sharing options...
shacker Posted July 17, 2020 Author Share Posted July 17, 2020 actualizamos el tuto con algunas mejoras Link to comment Share on other sites More sharing options...
Nedned Posted July 17, 2020 Share Posted July 17, 2020 Muy chulo, así no se inventan el nombre , que alguno me cambia de ciudad Link to comment Share on other sites More sharing options...
shacker Posted July 18, 2020 Author Share Posted July 18, 2020 es verdad jajaja Link to comment Share on other sites More sharing options...
Jeoz Posted July 29, 2020 Share Posted July 29, 2020 (edited) Hola! Es que ya hice todos los pasos pero no me aparecen las ciudades para seleccionar y tampoco me despliega el carrito de compra. Me pueden ayudar? Edited July 29, 2020 by Jeoz esa no era la imagen (see edit history) Link to comment Share on other sites More sharing options...
oharryo Posted September 10, 2020 Share Posted September 10, 2020 Gracias @shacker y @luishuaymana por compartir tanto con la comunidad. Link to comment Share on other sites More sharing options...
shacker Posted September 12, 2020 Author Share Posted September 12, 2020 gracias Link to comment Share on other sites More sharing options...
jitoru06 Posted September 18, 2020 Share Posted September 18, 2020 (edited) Gracias por este gran aporte, Lo intente pero no me funciono, Revisando el codigo, (pero no soy experto en esto) encontre el que creo puede ser el problema. en esta parte: y añadiremos al final elseif ($entity === 'city') { $formField->setType('select'); $formField->setName('id_' . strtolower($entity)); $cities = State::getCities(315); foreach ($cities as $city) { $formField->addAvailableValue( $city['id_city'], $city[$entityField] ); } $formField->setRequired(false); creo que se hace un llamado a la funcion State::getCities(315) el cual creo que es el error ya que siempre mostraria los datos pero solo para el id_state 315 no se como solucionarlo ya que no soy esperto en el tema, lo intente cambiando el valor 315 por una variable id_state pero no supe como hacerlo. de antemano gracias por la ayuda y agradezco nuevamente este gran aporte a la comunidad. saludos Edited September 18, 2020 by jitoru06 (see edit history) Link to comment Share on other sites More sharing options...
shacker Posted September 26, 2021 Author Share Posted September 26, 2021 On 9/18/2020 at 6:41 PM, jitoru06 said: Gracias por este gran aporte, Lo intente pero no me funciono, Revisando el codigo, (pero no soy experto en esto) encontre el que creo puede ser el problema. en esta parte: y añadiremos al final elseif ($entity === 'city') { $formField->setType('select'); $formField->setName('id_' . strtolower($entity)); $cities = State::getCities(315); foreach ($cities as $city) { $formField->addAvailableValue( $city['id_city'], $city[$entityField] ); } $formField->setRequired(false); creo que se hace un llamado a la funcion State::getCities(315) el cual creo que es el error ya que siempre mostraria los datos pero solo para el id_state 315 no se como solucionarlo ya que no soy esperto en el tema, lo intente cambiando el valor 315 por una variable id_state pero no supe como hacerlo. de antemano gracias por la ayuda y agradezco nuevamente este gran aporte a la comunidad. saludos Ese valor es solo para tener un valor por defecto al completar el form Link to comment Share on other sites More sharing options...
ocio87 Posted May 2, 2022 Share Posted May 2, 2022 Buenas tardes, Me podrían colaborar indicandome si este despliegue sirve en la versión 1.7.8.5 ya que actualmente hago los cambios y arroja el siguiente error cuando intento ingresar el nuevo campo de Ciudad: Link to comment Share on other sites More sharing options...
DNK-LUIFER Posted June 7, 2022 Share Posted June 7, 2022 En 2/5/2022 a las 9:05 PM, ocio87 dijo: Buenas tardes, Me podrían colaborar indicandome si este despliegue sirve en la versión 1.7.8.5 ya que actualmente hago los cambios y arroja el siguiente error cuando intento ingresar el nuevo campo de Ciudad: No podrás hacerlo desde backoffice. Tienes que editar desde phpmyadmin como explica en el manual. Link to comment Share on other sites More sharing options...
luismart6424 Posted December 28, 2023 Share Posted December 28, 2023 On 29/7/2020 at 15:29, Jeoz said: ¡Hola! Es que ya hice todos los pasos pero no me aparecen las ciudades para seleccionar y tampoco me despliega el carrito de compra. ¿Me pueden ayudar? buenas tardes me pasa igual hice todo el procedimiento pero no me deja ver las ciudades que cree tienen alguna solucion para esto? Link to comment Share on other sites More sharing options...
DNK-LUIFER Posted December 28, 2023 Share Posted December 28, 2023 hace 10 horas, luismart6424 dijo: buenas tardes me pasa igual hice todo el procedimiento pero no me deja ver las ciudades que cree tienen alguna solucion para esto? Hola. Hay que afinar mucho a la hora de situar el script en el .tpl: themes/nuestrotheme/templates/_partials/javascript.tpl Yo lo inserto directamente con {LITERAL} script {/LITERAL} al final del fichero. Tambíen puedes intertar cargar el script donde carga el formulario. Saludos. Link to comment Share on other sites More sharing options...
luismart6424 Posted December 28, 2023 Share Posted December 28, 2023 (edited) buena noches a mi me sale solo el listado del id_state que coloque por defecto osea no se modifica cuando yo seleciono otro id_state sera que me equivoque en algo? Edited December 29, 2023 by luismart6424 me sale un erro diferente ahora (see edit history) Link to comment Share on other sites More sharing options...
luismart6424 Posted April 27 Share Posted April 27 tengo una duda a mi el desarrollo me funciona correctamente pero queria saber si hay forma de enviar el ID de la ciudad en vez de el nombre de la ciudad , osea que el cliente vea el nombre pero se guarde el ID , o que el campo ID se guarde en otro campo Link to comment Share on other sites More sharing options...
RodDev Posted May 5 Share Posted May 5 Una consulta el codigo para cual version de prestashop esta verificado? Link to comment Share on other sites More sharing options...
shacker Posted August 11 Author Share Posted August 11 1.6, para 1.7 tambien puede utilizarse 1 Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now