*/ class CreditNoteController extends BaseAdminController { use CriteriaSearchHelper; /** * @param Request $request * @return \Thelia\Core\HttpFoundation\Response */ public function listAction(Request $request) { return $this->render( "credit-note-list", [ ] ); } /** * @param Request $request * @param int $id * @return \Thelia\Core\HttpFoundation\Response */ public function viewAction(Request $request, $id) { $creditNote = CreditNoteQuery::create() ->filterById($id, Criteria::EQUAL) ->findOne(); $creditNote = $this->performCreditNote($creditNote); return $this->render("ajax/credit-note-modal", [ 'creditNote' => $creditNote ]); } public function createAction(Request $request) { $creditNote = $this->performCreditNote(); $con = Propel::getServiceContainer()->getWriteConnection(CreditNoteTableMap::DATABASE_NAME); // use transaction because $criteria could contain info // for more than one table (I guess, conceivably) $con->beginTransaction(); try { $creditNote->save(); $con->commit(); } catch (\Exception $e) { $con->rollBack(); throw $e; } if (null !== $request->get('success-url')) { return new RedirectResponse($request->get('success-url')); } if (null !== $creditNote->getOrder()) { return $this->generateRedirectFromRoute( 'admin.order.update.view', [ 'tab' => 'credit-note' ], [ 'order_id' => $creditNote->getOrder()->getId() ] ); } if (null !== $creditNote->getCustomer()) { return $this->generateRedirectFromRoute('admin.customer.update.view', [], [ 'customer_id' => $creditNote->getCustomer()->getId() ]); } } public function updateAction(Request $request, $id) { $creditNote = CreditNoteQuery::create() ->filterById($id, Criteria::EQUAL) ->findOne(); $creditNote = $this->performCreditNote($creditNote); $con = Propel::getServiceContainer()->getWriteConnection(CreditNoteTableMap::DATABASE_NAME); // use transaction because $criteria could contain info // for more than one table (I guess, conceivably) $con->beginTransaction(); try { $creditNote->save(); $con->commit(); } catch (\Exception $e) { $con->rollBack(); throw $e; } if (null !== $request->get('success-url')) { return new RedirectResponse($request->get('success-url')); } if (null !== $creditNote->getOrder()) { return $this->generateRedirectFromRoute( 'admin.order.update.view', [ 'tab' => 'credit-note' ], [ 'order_id' => $creditNote->getOrder()->getId() ] ); } if (null !== $creditNote->getCustomer()) { return $this->generateRedirectFromRoute('admin.customer.update.view', [], [ 'customer_id' => $creditNote->getCustomer()->getId() ]); } } public function deleteAction(Request $request, $id) { $creditNote = CreditNoteQuery::create()->findOneById($id); if (!empty($creditNote->getInvoiceRef())) { $request->getSession()->getFlashBag()->set( 'error', $this->getTranslator()->trans( "You can not delete this credit note" ) ); } else { CreditNoteQuery::create()->filterById($id)->delete(); } if (null !== $request->get('success-url')) { return new RedirectResponse($request->get('success-url')); } if (null !== $creditNote->getOrder()) { return $this->generateRedirectFromRoute( 'admin.order.update.view', [ 'tab' => 'credit-note' ], [ 'order_id' => $creditNote->getOrder()->getId() ] ); } if (null !== $creditNote->getCustomer()) { return $this->generateRedirectFromRoute('admin.customer.update.view', [], [ 'customer_id' => $creditNote->getCustomer()->getId() ]); } } /** * @param Request $request * @return \Thelia\Core\HttpFoundation\Response */ public function ajaxModalCreateAction(Request $request) { $creditNote = $this->performCreditNote(); return $this->render("ajax/credit-note-modal", [ 'creditNote' => $creditNote ]); } public function generateInvoicePdfAction($creditNoteId, $browser) { return $this->generateCreditNotePdf($creditNoteId, 'credit-note', true, true, $browser); } /** * @param int $creditNoteId * @param string $fileName * @param bool $checkCreditNoteStatus * @param bool $checkAdminUser * @return \Symfony\Component\HttpFoundation\Response */ protected function generateCreditNotePdf($creditNoteId, $fileName, $checkCreditNoteStatus = true, $checkAdminUser = true, $browser = false) { $creditNote = CreditNoteQuery::create()->findPk($creditNoteId); // check if the order has the paid status if ($checkAdminUser && !$this->getSecurityContext()->hasAdminUser()) { throw new NotFoundHttpException(); } if ($checkCreditNoteStatus && !$creditNote->getCreditNoteStatus()->getInvoiced()) { throw new NotFoundHttpException(); } $html = $this->renderRaw( $fileName, [ 'credit_note_id' => $creditNote->getId() ], $this->getTemplateHelper()->getActivePdfTemplate() ); if ((int) $browser === 2) { return new Response($html); } try { $pdfEvent = new PdfEvent($html); $this->dispatch(TheliaEvents::GENERATE_PDF, $pdfEvent); if ($pdfEvent->hasPdf()) { if ((int) $browser === 1) { $browser = true; } else { $browser = false; } return $this->pdfResponse($pdfEvent->getPdf(), $creditNote->getInvoiceRef(), 200, $browser); } } catch (\Exception $e) { Tlog::getInstance()->error( sprintf( 'error during generating invoice pdf for credit note id : %d with message "%s"', $creditNote->getId(), $e->getMessage() ) ); } throw new TheliaProcessException( $this->getTranslator()->trans( "We're sorry, this PDF invoice is not available at the moment." ) ); } /** * @return CreditNote */ protected function performCreditNote(CreditNote $creditNote = null) { if (null === $creditNote) { $creditNote = new CreditNote(); } $creditNote->setDispatcher($this->getDispatcher()); $form = $this->createForm('credit-note.create', 'form', [], ['csrf_protection' => false]); $formValidate = $this->validateForm($form, 'post'); if (null === $creditNote->getInvoiceRef()) { $this ->performType($formValidate, $creditNote) ->performOrder($formValidate, $creditNote) ->performCurrency($formValidate, $creditNote) ->performCustomer($formValidate, $creditNote) ->performInvoiceAddress($formValidate, $creditNote) ->performStatus($formValidate, $creditNote) ->performFreeAmounts($formValidate, $creditNote) ->performOrderProducts($formValidate, $creditNote) ->performDiscount($formValidate, $creditNote) ->performAmount($formValidate, $creditNote) ; } $this->performComment($formValidate, $creditNote); $this->getParserContext()->addForm($form); $creditNote->setDispatcher($this->getDispatcher()); return $creditNote; } protected function performDiscount(Form $formValidate, CreditNote $creditNote) { $discountWithoutTax = $formValidate->get('discount_without_tax')->getData(); $discountWithTax = $formValidate->get('discount_with_tax')->getData(); if (null !== $creditNote->getOrder() && $creditNote->getCreditNoteType()->getCode() === CreditNoteHelper::TYPE_ORDER_FULL_REFUND) { $creditNote->setDiscountWithoutTax($creditNote->getOrder()->getDiscount()); $creditNote->setDiscountWithTax($creditNote->getOrder()->getDiscount()); } elseif (null !== $discountWithoutTax && null !== $discountWithTax) { $creditNote->setDiscountWithoutTax($discountWithoutTax); $creditNote->setDiscountWithTax($discountWithTax); } elseif (null === $creditNote->getOrder()) { $creditNote->setDiscountWithoutTax(0); $creditNote->setDiscountWithTax(0); } return $this; } protected function performInvoiceAddress(Form $formValidate, CreditNote $creditNote) { if (!empty($creditNote->getInvoiceRef())) { return $this; } $action = $formValidate->get('action')->getData(); $invoiceAddressId = $formValidate->get('invoice_address_id')->getData(); if ($action !== 'view') { $creditNoteAddress = $creditNote->getCreditNoteAddress(); if (null === $creditNoteAddress) { $creditNoteAddress = new CreditNoteAddress(); } if (null === $creditNote->getCustomer()) { $creditNoteAddress = new CreditNoteAddress(); } elseif ($invoiceAddressId) { $address = AddressQuery::create()->findOneById((int)$invoiceAddressId); $customerTitle = $address->getCustomerTitle(); $creditNoteAddress ->setCustomerTitleId($customerTitle ? $customerTitle->getId() : null) ->setAddress1($address->getAddress1()) ->setAddress2($address->getAddress2()) ->setAddress3($address->getAddress3()) ->setFirstname($address->getFirstname()) ->setLastname($address->getLastname()) ->setCity($address->getCity()) ->setZipcode($address->getZipcode()) ->setCompany($address->getCompany()) ->setCountryId($address->getCountry()->getId()); } else { $invoiceAddressTitle = $formValidate->get('invoice_address_title')->getData(); $invoiceAddressFirstname = $formValidate->get('invoice_address_firstname')->getData(); $invoiceAddressLastname = $formValidate->get('invoice_address_lastname')->getData(); $invoiceAddressCompany = $formValidate->get('invoice_address_company')->getData(); $invoiceAddressAddress1 = $formValidate->get('invoice_address_address1')->getData(); $invoiceAddressAddress2 = $formValidate->get('invoice_address_address2')->getData(); $invoiceAddressZipcode = $formValidate->get('invoice_address_zipcode')->getData(); $invoiceAddressCity = $formValidate->get('invoice_address_city')->getData(); $invoiceAddressCountryId = $formValidate->get('invoice_address_country_id')->getData(); $country = CountryQuery::create()->findOneById($invoiceAddressCountryId); $creditNoteAddress ->setCustomerTitleId($invoiceAddressTitle) ->setAddress1($invoiceAddressAddress1) ->setAddress2($invoiceAddressAddress2) ->setFirstname($invoiceAddressFirstname) ->setLastname($invoiceAddressLastname) ->setCity($invoiceAddressCity) ->setZipcode($invoiceAddressZipcode) ->setCompany($invoiceAddressCompany) ->setCountryId( $country ? $country->getId() : null ); } if (empty($creditNoteAddress->getLastname()) && ('create' === $action || 'update' === $action)) { $formValidate->addError( new FormError('Please select a invoice address') ); $creditNoteAddress->save(); } $creditNote->setCreditNoteAddress($creditNoteAddress); } elseif (null === $creditNote->getId()) { if (null !== $creditNote->getOrder() && null === $creditNote->getCreditNoteAddress()) { $address = $creditNote->getOrder()->getOrderAddressRelatedByInvoiceOrderAddressId(); $customerTitle = $address->getCustomerTitle(); $creditNoteAddress = new CreditNoteAddress(); $creditNoteAddress ->setCustomerTitleId($customerTitle ? $customerTitle->getId() : null) ->setAddress1($address->getAddress1()) ->setAddress2($address->getAddress2()) ->setAddress3($address->getAddress3()) ->setFirstname($address->getFirstname()) ->setLastname($address->getLastname()) ->setCity($address->getCity()) ->setZipcode($address->getZipcode()) ->setCompany($address->getCompany()) ->setCountryId($address->getCountry()->getId()); $creditNote->setCreditNoteAddress($creditNoteAddress); } else { $creditNote->setCreditNoteAddress(new CreditNoteAddress()); } } return $this; } protected function performAmount(Form $formValidate, CreditNote $creditNote) { $totalPrice = 0; $totalPriceWithTax = 0; foreach ($creditNote->getCreditNoteDetails() as $creditNoteDetail) { $totalPrice += $creditNoteDetail->getPrice() * $creditNoteDetail->getQuantity(); $totalPriceWithTax += $creditNoteDetail->getPriceWithTax() * $creditNoteDetail->getQuantity(); } $totalPrice -= $creditNote->getDiscountWithoutTax(); $totalPriceWithTax -= $creditNote->getDiscountWithTax(); $creditNote->setTotalPrice($totalPrice); $creditNote->setTotalPriceWithTax($totalPriceWithTax); return $this; } protected function performComment(Form $formValidate, CreditNote $creditNote) { /** @var string $orderId */ $comment = trim($formValidate->get('comment')->getData()); if (null !== $comment && !empty($comment)) { $creditNote->addCreditNoteComment( (new CreditNoteComment()) ->setComment($comment) ->setAdminId($this->getSecurityContext()->getAdminUser()->getId()) ); } return $this; } protected function performOrder(Form $formValidate, CreditNote $creditNote) { /** @var int $orderId */ $orderId = $formValidate->get('order_id')->getData(); if (null !== $orderId && !empty($orderId)) { $order = OrderQuery::create()->findPk($orderId); $creditNote ->setOrder($order) ->setCustomer($order->getCustomer()) ->setCurrency($order->getCurrency()); if ($order->getStatusId() == 1 || $order->getStatusId() == 5) { throw new \Exception('This order is not invoiced'); } } return $this; } protected function performCurrency(Form $formValidate, CreditNote $creditNote) { /** @var int $currencyId */ $currencyId = $formValidate->get('currency_id')->getData(); if (null !== $creditNote->getOrder()) { $creditNote->setCurrency($creditNote->getOrder()->getCurrency()); } elseif ($creditNote->getCurrency() === null) { if (!empty($currencyId) && $currency = CurrencyQuery::create()->findPk($currencyId)) { $creditNote->setCurrency($currency); } else { $creditNote->setCurrency(CurrencyQuery::create()->findOneByByDefault(true)); } } return $this; } protected function performCustomer(Form $formValidate, CreditNote $creditNote) { /** @var int $customerId */ $customerId = $formValidate->get('customer_id')->getData(); // check if order if (!empty($orderId) && null !== $order = OrderQuery::create()->findPk($orderId)) { $creditNote ->setOrder($order) ->setCurrency($order->getCurrency()) ->setCustomer($order->getCustomer()); } elseif (!empty($customerId) && null !== $customer = CustomerQuery::create()->findPk($customerId)) { $creditNote->setCustomer($customer); } return $this; } protected function performType(Form $formValidate, CreditNote $creditNote) { /** @var int $typeId */ $typeId = $formValidate->get('type_id')->getData(); if (!empty($typeId) && null !== $type = CreditNoteTypeQuery::create()->findPk($typeId)) { $creditNote->setCreditNoteType($type); } elseif (null === $creditNote->getTypeId()) { $creditNote->setCreditNoteType(CreditNoteTypeQuery::create()->findOne()); } return $this; } protected function performStatus(Form $formValidate, CreditNote $creditNote) { /** @var int $statusId */ $statusId = $formValidate->get('status_id')->getData(); if (!empty($statusId) && null !== $status = CreditNoteStatusQuery::create()->findPk($statusId)) { $creditNote->setCreditNoteStatus($status); } elseif (null === $creditNote->getStatusId()) { $creditNote->setCreditNoteStatus(CreditNoteStatusQuery::create()->findOne()); } return $this; } protected function performFreeAmounts(Form $formValidate, CreditNote $creditNote) { /** @var string[] $freeAmountTitles */ $freeAmountTitles = $formValidate->get('free_amount_title')->getData(); /** @var float[] $freeAmountPrices */ $freeAmountPrices = $formValidate->get('free_amount_price')->getData(); /** @var float[] $freeAmountPricesWithTax */ $freeAmountPricesWithTax = $formValidate->get('free_amount_price_with_tax')->getData(); /** @var int[] $freeAmountTaxRuleIds */ $freeAmountTaxRuleIds = $formValidate->get('free_amount_tax_rule_id')->getData(); /** @var string[] $freeAmountTaxRuleIds */ $freeAmountIds = $formValidate->get('free_amount_id')->getData(); /** @var string[] $freeAmountTypes */ $freeAmountTypes = $formValidate->get('free_amount_type')->getData(); /** @var string $freeAmountTypes */ $action = $formValidate->get('action')->getData(); foreach ($creditNote->getCreditNoteDetails() as $creditNoteDetail) { if (empty($creditNoteDetail->getOrderProductId())) { foreach ($freeAmountTitles as $key => $freeAmountTitle) { if ($freeAmountIds[$key] == $creditNoteDetail->getId()) { $creditNoteDetail ->setTitle($freeAmountTitle) ->setPrice($freeAmountPrices[$key]) ->setTaxRuleId($freeAmountTaxRuleIds[$key]) ->setType($freeAmountTypes[$key]) ->setPriceWithTax($freeAmountPricesWithTax[$key]); } } } } /** * @var int $key * @var int $freeAmountTitle */ foreach ($freeAmountTitles as $key => $freeAmountTitle) { if (empty($freeAmountIds[$key])) { $creditNote->addCreditNoteDetail( (new CreditNoteDetail()) ->setTitle($freeAmountTitle) ->setPrice($freeAmountPrices[$key]) ->setTaxRuleId($freeAmountTaxRuleIds[$key]) ->setType($freeAmountTypes[$key]) ->setQuantity(1) ->setPriceWithTax($freeAmountPricesWithTax[$key]) ); } } if (null !== $creditNote->getOrder() && $creditNote->getCreditNoteType()->getCode() === CreditNoteHelper::TYPE_ORDER_FULL_REFUND) { if (!(float) $creditNote->getOrder()->getPostage()) { foreach ($creditNote->getCreditNoteDetails() as $creditNoteDetail) { if ($creditNoteDetail->getType() == 'shipping') { $creditNote->removeCreditNoteDetail($creditNoteDetail); } } } else { $findShipping = false; foreach ($creditNote->getCreditNoteDetails() as $creditNoteDetail) { if ($creditNoteDetail->getType() == 'shipping') { $findShipping = true; $creditNoteDetail ->setPrice( $creditNote->getOrder()->getPostage() - $creditNote->getOrder()->getPostageTax() ) ->setPriceWithTax( $creditNote->getOrder()->getPostage() ); } } if (!$findShipping) { $creditNote->addCreditNoteDetail( (new CreditNoteDetail()) ->setQuantity(1) ->setTitle('Frais de port') ->setPrice($creditNote->getOrder()->getPostage() - $creditNote->getOrder()->getPostageTax()) ->setType('shipping') ->setPriceWithTax($creditNote->getOrder()->getPostage()) ); } } } if ('refresh' === $action || $action === 'update') { foreach ($creditNote->getCreditNoteDetails() as $creditNoteDetail) { $find = false; if (empty($creditNoteDetail->getOrderProductId())) { foreach ($freeAmountTitles as $key => $freeAmountTitle) { if ($freeAmountIds[$key] == $creditNoteDetail->getId()) { $find = true; } } if (!$find) { $creditNote->removeCreditNoteDetail($creditNoteDetail); } } } } return $this; } /** * @param Form $formValidate * @param CreditNote $creditNote * @return $this */ protected function performOrderProducts(Form $formValidate, CreditNote $creditNote) { if (null === $creditNote->getOrder()) { return $this; } /** @var string $freeAmountTypes */ $action = $formValidate->get('action')->getData(); /** @var int[] $orderProductQuantities */ $orderProductQuantities = $formValidate->get('order_product_quantity')->getData(); foreach ($creditNote->getOrder()->getOrderProducts() as $orderProduct) { $creditNoteDetail = null; if (null !== $creditNote->getId()) { $creditNoteDetail = CreditNoteDetailQuery::create() ->filterByCreditNoteId($creditNote->getId()) ->filterByOrderProductId($orderProduct->getId()) ->findOne(); } if (null === $creditNoteDetail) { $creditNoteDetail = new CreditNoteDetail; } if ($creditNote->getCreditNoteType()->getCode() === CreditNoteHelper::TYPE_ORDER_FULL_REFUND) { $creditNoteDetail->setQuantity($orderProduct->getQuantity()); } else { if (isset($orderProductQuantities[$orderProduct->getId()])) { $creditNoteDetail->setQuantity($orderProductQuantities[$orderProduct->getId()]); } } if ((float) $creditNoteDetail->getQuantity() <= 0) { $creditNote->removeCreditNoteDetail($creditNoteDetail); continue; } if ((int) $orderProduct->getWasInPromo()) { $orderProductWithoutTax = ((float) $orderProduct->getPromoPrice()); $orderProductWithTax = (float) $orderProduct->getPromoPrice(); } else { $orderProductWithoutTax = ((float) $orderProduct->getPrice()); $orderProductWithTax = (float) $orderProduct->getPrice(); } $orderProductTaxes = $orderProduct->getOrderProductTaxes(); /** @var OrderProductTax $orderProductTax */ foreach ($orderProductTaxes as $orderProductTax) { if ((int) $orderProduct->getWasInPromo()) { $orderProductWithTax += (float) $orderProductTax->getPromoAmount(); } else { $orderProductWithTax += (float) $orderProductTax->getAmount(); } } $creditNoteDetail ->setOrderProduct($orderProduct) ->setTitle($orderProduct->getTitle()) ->setPrice($orderProductWithoutTax) ->setType('product') ->setPriceWithTax($orderProductWithTax); if (null !== $pse = ProductSaleElementsQuery::create()->findOneById($orderProduct->getProductSaleElementsId())) { if ($pse->getProduct() === null) { $creditNoteDetail->setTaxRuleId(TaxRuleQuery::create()->findOneByIsDefault(true)->getId()); } else { $creditNoteDetail ->setTaxRuleId( $pse ->getProduct() ->getTaxRuleId() ) ; } } $creditNote->addCreditNoteDetail( $creditNoteDetail ); } if ($action === 'update') { foreach ($creditNote->getCreditNoteDetails() as $creditNoteDetail) { if ((float) $creditNoteDetail->getQuantity() === 0.0 && $creditNoteDetail->getType() === 'product') { $creditNote->removeCreditNoteDetail($creditNoteDetail); } } } return $this; } /** * @param Request $request * @return JsonResponse * @throws \Propel\Runtime\Exception\PropelException */ public function searchCustomerAction(Request $request) { $customerQuery = CustomerQuery::create() ->innerJoinAddress() ->groupById() ->limit(20); $this->whereConcatRegex($customerQuery, [ 'customer.FIRSTNAME', 'customer.LASTNAME', 'customer.EMAIL', 'address.COMPANY', 'address.PHONE' ], $request->get('q')); $customerQuery ->withColumn(AddressTableMap::COMPANY, 'COMPANY') ->withColumn(AddressTableMap::ADDRESS1, 'ADDRESS') ->withColumn(AddressTableMap::CITY, 'CITY') ->withColumn(AddressTableMap::ZIPCODE, 'ZIPCODE') ->withColumn(AddressTableMap::PHONE, 'PHONE'); $customers = $customerQuery->find(); $json = [ 'incomplete_results' => count($customers) ? false : true, 'items' => [] ]; /** @var Customer $customer */ foreach ($customers as $customer) { $json['items'][] = [ 'id' => $customer->getId(), 'company' => $customer->getVirtualColumn('COMPANY'), 'firstname' => $customer->getFirstname(), 'lastname' => $customer->getLastname(), 'ref' => $customer->getRef(), 'address' => $this->formatAddress($customer) ]; } return new JsonResponse($json); } /** * @param Request $request * @return JsonResponse * @throws \Propel\Runtime\Exception\PropelException */ public function searchOrderAction(Request $request) { $orderQuery = OrderQuery::create(); //$orderQuery->filterByInvoiceRef(null, Criteria::ISNOTNULL); $orderQuery->useOrderStatusQuery() ->filterById([1,5], Criteria::NOT_IN) ->endUse(); if (null !== $customerId = $request->get('customerId')) { if ((int) $customerId > 0) { $orderQuery->filterByCustomerId((int) $customerId); } } $orderQuery->innerJoinOrderAddressRelatedByInvoiceOrderAddressId() ->groupById() ->limit(20); $this->whereConcatRegex($orderQuery, [ 'order.REF', 'order_address.LASTNAME', 'order_address.FIRSTNAME', 'order_address.COMPANY', 'order_address.PHONE' ], $request->get('q')); $orderQuery ->withColumn(OrderAddressTableMap::FIRSTNAME, 'FIRSTNAME') ->withColumn(OrderAddressTableMap::LASTNAME, 'LASTNAME') ->withColumn(OrderAddressTableMap::COMPANY, 'COMPANY') ->withColumn(OrderAddressTableMap::ADDRESS1, 'ADDRESS') ->withColumn(OrderAddressTableMap::CITY, 'CITY') ->withColumn(OrderAddressTableMap::ZIPCODE, 'ZIPCODE') ->withColumn(OrderAddressTableMap::PHONE, 'PHONE'); $orders = $orderQuery->find(); $json = [ 'incomplete_results' => count($orders) ? false : true, 'items' => [] ]; /** @var Order $order */ foreach ($orders as $order) { $json['items'][] = [ 'id' => $order->getId(), 'ref' => $order->getRef(), 'company' => $order->getVirtualColumn('COMPANY'), 'firstname' => $order->getVirtualColumn('FIRSTNAME'), 'lastname' => $order->getVirtualColumn('LASTNAME'), 'address' => $this->formatAddress($order), ]; } return new JsonResponse($json); } /** * @param ActiveRecordInterface $model * @return mixed */ protected function formatAddress(ActiveRecordInterface $model) { /** @var Order|Customer $model */ return implode(' ', [$model->getVirtualColumn('ADDRESS'), $model->getVirtualColumn('ZIPCODE'), $model->getVirtualColumn('CITY')]); } }