From: konrad Date: Tue, 5 Jan 2010 16:15:59 +0000 (+0000) Subject: cart tab almost functional, create order in php missing, create reservation missing... X-Git-Url: http://git.silmor.de/gitweb/?a=commitdiff_plain;h=2997f15e6b5e3f79e9a3b700eb6ce67084d3158e;p=konrad%2Fsmoke.git cart tab almost functional, create order in php missing, create reservation missing on both sides git-svn-id: https://silmor.de/svn/softmagic/smoke/trunk@405 6e3c4bff-ac9f-4ac1-96c5-d2ea494d3e33 --- diff --git a/src/dialogs/customerdlg.cpp b/src/dialogs/customerdlg.cpp index 47621ec..2ef4d9d 100644 --- a/src/dialogs/customerdlg.cpp +++ b/src/dialogs/customerdlg.cpp @@ -91,8 +91,11 @@ void MCustomerListDialog::updateList(int nid) //check for current selection if(nid<0){ QModelIndex idx=m_listview->currentIndex(); - if(idx.isValid()) - nid=m_proxymodel->data(idx,Qt::UserRole).toInt(); + if(idx.isValid()){ + int i=m_proxymodel->data(idx,Qt::UserRole).toInt(); + if(i>=0&&iqueryGetAllCustomerNames(); @@ -736,3 +739,52 @@ void MAddressDialog::selectCountry() m_addr.setcountryid(m_addr.country().value().id()); m_country->setText(m_addr.country().value().name()); } + +/*****************************************************************************/ + +MAddressChoiceDialog::MAddressChoiceDialog(QWidget*par,const MOCustomer&c) + :QDialog(par),m_cust(c) +{ + m_needupdate=false; + setWindowTitle(tr("Chose an Address")); + QHBoxLayout*hl; + QVBoxLayout*vl; + setLayout(vl=new QVBoxLayout); + vl->addWidget(m_lwidget=new MAddressListWidget(this,m_cust.addresses(),true),10); + connect(m_lwidget,SIGNAL(addressChanged(const MOAddress&)),this,SLOT(changed())); + connect(m_lwidget,SIGNAL(addressDeleted(const MOAddress&)),this,SLOT(changed())); + connect(m_lwidget,SIGNAL(addressCreated(const MOAddress&)),this,SLOT(changed())); + connect(m_lwidget,SIGNAL(addressEdited(const MOAddress&)),this,SLOT(changed())); + //on selection: first update customer, then close window + connect(m_lwidget,SIGNAL(addressSelected(qint64)),this,SLOT(updateCustomer()),Qt::DirectConnection); + + vl->addLayout(hl=new QHBoxLayout,0); + hl->addStretch(10); + QPushButton*p; + hl->addWidget(p=new QPushButton(tr("Add Address")),0); + connect(p,SIGNAL(clicked()),m_lwidget,SLOT(createAddress())); + hl->addSpacing(20); + hl->addWidget(p=new QPushButton(tr("Cancel")),0); + connect(p,SIGNAL(clicked()),this,SLOT(reject())); +} + +MOAddress MAddressChoiceDialog::address()const{return m_lwidget->selection();} +qint64 MAddressChoiceDialog::addressId()const{return m_lwidget->selection().addressid();} +void MAddressChoiceDialog::changed(){m_needupdate=true;} + +void MAddressChoiceDialog::updateCustomer() +{ + setEnabled(false); + if(m_needupdate){ + //do update + m_cust.setaddresses(m_lwidget->addressList()); + MTChangeCustomer cc=MTChangeCustomer::query(m_cust); + if(cc.hasError()){ + QMessageBox::warning(this,tr("Warning"),tr("Unable to save changes made to addresses: %1").arg(cc.errorString())); + return; + } + m_cust=cc.getcustomer(); + } + //close dialog successfully + accept(); +} diff --git a/src/dialogs/customerdlg.h b/src/dialogs/customerdlg.h index c456f7b..88775a6 100644 --- a/src/dialogs/customerdlg.h +++ b/src/dialogs/customerdlg.h @@ -181,6 +181,33 @@ class MAddressListWidget:public QScrollArea QGridLayout*m_layout; }; +/**wrapper dialog to chose an address; updates the customer is there is a change*/ +class MAddressChoiceDialog:public QDialog +{ + Q_OBJECT + public: + /**creates the dialog*/ + MAddressChoiceDialog(QWidget*,const MOCustomer&); + + /**returns the chosen address*/ + MOAddress address()const; + + /**returns the ID of the chosen address*/ + qint64 addressId()const; + + /**returns the (modified) customer object*/ + MOCustomer customer()const{return m_cust;} + private slots: + /**internal: notified if there is a change to the address list*/ + void changed(); + /**internal: updates the customer if necessary*/ + void updateCustomer(); + private: + MOCustomer m_cust; + bool m_needupdate; + MAddressListWidget*m_lwidget; +}; + /**dialog for editing exactly one address*/ class MAddressDialog:public QDialog { diff --git a/src/mwin/carttab.cpp b/src/mwin/carttab.cpp index 3b1566e..89d29ee 100644 --- a/src/mwin/carttab.cpp +++ b/src/mwin/carttab.cpp @@ -36,6 +36,7 @@ MCartTab::MCartTab(QString pk) { profilekey=pk; + deliveryaddrid=invoiceaddrid=-1; QVBoxLayout*vl;QHBoxLayout*hl; QPushButton*p; @@ -56,7 +57,12 @@ MCartTab::MCartTab(QString pk) connect(p,SIGNAL(clicked()),this,SLOT(cartAddTicket())); hl2->addWidget(p=new QPushButton(tr("Add Voucher")),0); connect(p,SIGNAL(clicked()),this,SLOT(cartAddVoucher())); - hl2->addWidget(p=new QPushButton(tr("Remove Item")),0); + hl2->addWidget(p=new QPushButton(tr("Add Shop Item")),0); + //TODO: implement items + p->setEnabled(false); + connect(p,SIGNAL(clicked()),this,SLOT(cartAddItem())); + hl2->addSpacing(15); + hl2->addWidget(p=new QPushButton(tr("Remove Line")),0); connect(p,SIGNAL(clicked()),this,SLOT(cartRemoveItem())); QFrame*frm; hl->addWidget(frm=new QFrame,0); @@ -64,15 +70,23 @@ MCartTab::MCartTab(QString pk) hl->addLayout(vl2=new QVBoxLayout,1); vl2->addWidget(p=new QPushButton(tr("Customer:")),0); connect(p,SIGNAL(clicked()),this,SLOT(setCustomer())); - vl2->addWidget(cartcustomer=new QLabel("...\n \n \n ")); + vl2->addWidget(cartcustomer=new QLabel("...")); + vl2->addWidget(frm=new QFrame,0); + frm->setFrameShape(QFrame::HLine); + vl2->addWidget(p=new QPushButton(tr("Invoice Address:")),0); + connect(p,SIGNAL(clicked()),this,SLOT(setInvoiceAddr())); + vl2->addWidget(invoiceaddr=new QLabel("...")); + vl2->addWidget(frm=new QFrame,0); + frm->setFrameShape(QFrame::HLine); + vl2->addWidget(p=new QPushButton(tr("Delivery Address:")),0); + connect(p,SIGNAL(clicked()),this,SLOT(setDeliveryAddr())); + vl2->addWidget(deliveryaddr=new QLabel("...")); vl2->addWidget(frm=new QFrame,0); frm->setFrameShape(QFrame::HLine); vl2->addSpacing(10); vl2->addWidget(new QLabel(tr("Shipping Method:")),0); vl2->addWidget(cartship=new QComboBox,0); cartship->setEditable(false); - vl2->addWidget(new QLabel(tr("Delivery Address:")),0); - vl2->addWidget(cartaddr=new QTextEdit); vl2->addSpacing(10); vl2->addWidget(new QLabel(tr("Comments:")),0); vl2->addWidget(cartcomment=new QTextEdit); @@ -133,8 +147,11 @@ void MCartTab::initCart() //clear customer customer=MOCustomer(); cartcustomer->setText(""); - //clear address/comment - cartaddr->setPlainText(""); + //clear address + deliveryaddr->setText(""); + invoiceaddr->setText(""); + deliveryaddrid=invoiceaddrid=-1; + //clear comment cartcomment->setPlainText(""); //clear shipping cartship->setCurrentIndex(0); @@ -145,8 +162,42 @@ void MCartTab::setCustomer() MCustomerListDialog mcl(this,true,customer.id()); if(mcl.exec()!=QDialog::Accepted)return; customer=mcl.getCustomer(); - //TODO: follow up with address dialog -// cartcustomer->setText(customer.getNameAddress()); + cartcustomer->setText(customer.fullName()); + //clear address + deliveryaddr->setText(""); + invoiceaddr->setText(""); + deliveryaddrid=invoiceaddrid=-1; + //follow up with address dialog + if(!customer.customerid().isNull()) + setInvoiceAddr(); +} + +void MCartTab::setDeliveryAddr() +{ + if(customer.customerid().isNull()){ + QMessageBox::warning(this,tr("Warning"),tr("Please set the customer first.")); + return; + } + MAddressChoiceDialog d(this,customer); + if(d.exec()!=QDialog::Accepted)return; + customer=d.customer(); + deliveryaddr->setText(d.address().fullAddress(customer.fullName())); + deliveryaddrid=d.addressId(); +} + +void MCartTab::setInvoiceAddr() +{ + if(customer.customerid().isNull()){ + //customer not set yet, chose it + setCustomer(); + //the setCustomer routine will recurse back to here + return; + } + MAddressChoiceDialog d(this,customer); + if(d.exec()!=QDialog::Accepted)return; + customer=d.customer(); + invoiceaddr->setText(d.address().fullAddress(customer.fullName())); + invoiceaddrid=d.addressId(); } static const int CART_TICKET=1; @@ -218,7 +269,7 @@ void MCartTab::eventOrderTicket() } void MCartTab::cartAddVoucher() -{/*TODO +{ //create voucher selection dialog QDialog dlg; dlg.setWindowTitle(tr("Select Voucher")); @@ -227,13 +278,13 @@ void MCartTab::cartAddVoucher() QGridLayout*gl; QStandardItemModel mdl; QRegExpValidator regv(priceRegExp(),this); - QListprc=req->getVoucherPrices(); + QListprc=MTGetValidVoucherPrices::query().getprices(); mdl.insertRows(0,prc.size()); mdl.insertColumns(0,1); for(int i=0;iaddWidget(new QLabel(tr("Select voucher price and value:")),0,0,1,2); - if(req->hasRole("_anypricevoucher")){ + if(req->hasRight(req->PCreateOrder_DiffVoucherValuePrice)){ gl->addWidget(new QLabel(tr("Price:")),1,0); gl->addWidget(cp=new QComboBox,1,1); cp->setModel(&mdl); @@ -243,7 +294,7 @@ void MCartTab::cartAddVoucher() gl->addWidget(new QLabel(tr("Value:")),2,0); gl->addWidget(cv=new QComboBox,2,1); cv->setModel(&mdl); - cv->setEditable(req->hasRole("_anyvoucher")); + cv->setEditable(req->hasRight(req->PCreateOrder_AnyVoucherValue)); cv->setValidator(®v); gl->setRowMinimumHeight(3,15); gl->setColumnStretch(0,0); @@ -261,7 +312,7 @@ void MCartTab::cartAddVoucher() //get selection int price,value; value=str2cent(cv->currentText()); - if(req->hasRole("_anypricevoucher") && cp) + if(req->hasRight(req->PCreateOrder_DiffVoucherValuePrice) && cp) price=str2cent(cp->currentText()); else price=value; @@ -274,7 +325,12 @@ void MCartTab::cartAddVoucher() cartmodel->setData(cartmodel->index(cr,0),CART_VOUCHER,CART_TYPEROLE); cartmodel->setData(cartmodel->index(cr,1),tr("Voucher (price: %1, value %2)").arg(cent2str(price)).arg(cent2str(value))); carttable->resizeColumnsToContents(); - }*/ + } +} + +void MCartTab::cartAddItem() +{ + //TODO: implement items } void MCartTab::cartRemoveItem() @@ -288,7 +344,7 @@ void MCartTab::cartRemoveItem() void MCartTab::cartOrder() { -/* //sanity checks + //sanity checks if(cartmodel->rowCount()<1){ QMessageBox::warning(this,tr("Error"),tr("There is nothing in the order. Ignoring it.")); return; @@ -297,77 +353,49 @@ void MCartTab::cartOrder() QMessageBox::warning(this,tr("Error"),tr("Please chose a customer first!")); return; } + if(cartship->currentIndex()>0 && deliveryaddrid<0 && invoiceaddrid<0){ + if(QMessageBox::question(this,tr("Shipping"),tr("You have chosen a shipping method, but no address. Are you sure you want to continue?"),QMessageBox::Yes|QMessageBox::No) != QMessageBox::Yes)return; + } /////////////// //create order - QDomDocument doc; - QDomElement root=doc.createElement("Order"); - root.setAttribute("customer",customer.id()); + MOCartOrder cord; + cord.setcustomerid(customer.id()); //is there a delivery address - QString s=cartaddr->toPlainText().trimmed(); - if(s!=""){ - QDomElement da=doc.createElement("DeliveryAddress"); - da.appendChild(doc.createTextNode(s)); - root.appendChild(da); - } + if(deliveryaddrid>=0)cord.setdeliveryaddressid(deliveryaddrid); + if(invoiceaddrid>=0)cord.setinvoiceaddressid(invoiceaddrid); //is there a comment? - s=cartcomment->toPlainText().trimmed(); - if(s!=""){ - QDomElement cc=doc.createElement("Comment"); - cc.appendChild(doc.createTextNode(s)); - root.appendChild(cc); - } + QString s=cartcomment->toPlainText().trimmed(); + if(s!="")cord.setcomment(s); //scan tickets & scan vouchers for(int i=0;irowCount();i++){ QModelIndex idx=cartmodel->index(i,0); int tp=cartmodel->data(idx,CART_TYPEROLE).toInt(); if(tp==CART_TICKET){ - int amt=cartmodel->data(idx).toInt(); - int evid=cartmodel->data(idx,CART_IDROLE).toInt(); - for(int j=0;jdata(idx).toInt()); + ct.seteventid(cartmodel->data(idx,CART_IDROLE).toInt()); + cord.addtickets(ct); }else if(tp==CART_VOUCHER){ - int amt=cartmodel->data(idx).toInt(); - int price=cartmodel->data(idx,CART_PRICEROLE).toInt(); - int value=cartmodel->data(idx,CART_VALUEROLE).toInt(); - for(int j=0;jdata(idx).toInt()); + cv.setprice(cartmodel->data(idx,CART_PRICEROLE).toInt()); + cv.setvalue(cartmodel->data(idx,CART_VALUEROLE).toInt()); + cord.addvouchers(cv); } + //TODO: product/items } //set shipping info - if(cartship->currentIndex()>0){ - QDomElement si=doc.createElement("Shipping"); - si.setAttribute("type",cartship->itemData(cartship->currentIndex()).toInt()); - root.appendChild(si); - } - //finalize - doc.appendChild(root);*/ + cord.setshippingtypeid(cartship->itemData(cartship->currentIndex()).toInt()); //send - /*TODO - if(req->request("checkorder",doc.toByteArray())==false){ - QMessageBox::warning(this,tr("Error"),tr("The request failed.")); - return; - } - if(req->responseStatus()!=MSInterface::Ok){ - QMessageBox::warning(this,tr("Error"),tr("A problem occurred during the order: %1").arg(qApp->translate("php::",req->responseBody()))); + MTCreateOrder co=req->queryCreateOrder(cord); + if(co.hasError()){ + QMessageBox::warning(this,tr("Warning"),tr("Error while creating order: %1").arg(co.errorString())); return; } - //parse result - QDomDocument rdoc; - rdoc.setContent(req->responseBody()); - //display order and give user chance to actually order it - MOrderWindow *ow=new MOrderWindow(this,req,MOrder(req,rdoc.documentElement())); + initCart(); + MOrderWindow *ow=new MOrderWindow(window(),co.getorder()); ow->show(); - //empty the cart - initCart();*/ } /********************************************************************************/ diff --git a/src/mwin/carttab.h b/src/mwin/carttab.h index 4200e70..99a2365 100644 --- a/src/mwin/carttab.h +++ b/src/mwin/carttab.h @@ -73,12 +73,18 @@ class MCartTab:public QWidget private slots: /**decide what customer to use*/ void setCustomer(); + /**decide about delivery address*/ + void setDeliveryAddr(); + /**decide about invoice address*/ + void setInvoiceAddr(); /**initialize cart tab*/ void initCart(); /**add a ticket to the cart*/ void cartAddTicket(); /**add a voucher to the cart*/ void cartAddVoucher(); + /**add a product item to the cart*/ + void cartAddItem(); /**remove item from the cart*/ void cartRemoveItem(); /**check the order on the server*/ @@ -90,11 +96,12 @@ class MCartTab:public QWidget //widgets QTableView*carttable; QStandardItemModel*cartmodel; - QLabel*cartcustomer; - QTextEdit *cartaddr,*cartcomment; + QLabel*cartcustomer,*deliveryaddr,*invoiceaddr; + QTextEdit *cartcomment; QComboBox*cartship; //cart MOCustomer customer; + qint64 deliveryaddrid,invoiceaddrid; }; /**Helper class for shopping cart: allow editing amount, but nothing else*/ diff --git a/src/wext/MOCustomer.cpp b/src/wext/MOCustomer.cpp index 587bc76..6d487de 100644 --- a/src/wext/MOCustomer.cpp +++ b/src/wext/MOCustomer.cpp @@ -21,9 +21,11 @@ MOCustomer::MOCustomer(qint64 i) operator=(gc.getcustomer().value()); } -MOCustomer::MOCustomer(const MOCustomerInfo&i) +MOCustomer::MOCustomer(const MOCustomerInfo&ci) { - MOCustomer::MOCustomer(i.id()); + MTGetCustomer gc=req->queryGetCustomer(ci.id()); + if(gc.stage()==gc.Success) + operator=(gc.getcustomer().value()); } QString MOCustomer::address(int i) @@ -31,16 +33,21 @@ QString MOCustomer::address(int i) if(i<0)return ""; QListadrs=addresses(); if(i>=adrs.size())return ""; - QString ret; - MOAddress adr=adrs[i]; - if(adr.name().isNull())ret=name(); - else ret=adr.name().value(); - ret+="\n"; - if(!adr.addr1().isNull())ret+=adr.addr1().value()+"\n"; - if(!adr.addr2().isNull())ret+=adr.addr2().value()+"\n"; - if(!adr.city().isNull())ret+=adr.city().value()+"\n"; - if(!adr.state().isNull())ret+=adr.state().value()+"\n"; - if(!adr.zipcode().isNull())ret+=adr.zipcode().value()+"\n"; - if(!adr.country().isNull())ret+=adr.country().value().name(); + return adrs[i].fullAddress(fullName()); +} + +QString MOCustomer::fullName()const +{ + QString ret=title().value().trimmed(); + QString s=name().value().trimmed(); + if(s!=""){ + if(ret!="")ret+=" "; + ret+=s; + } + s=firstname().value().trimmed(); + if(s!=""){ + if(ret!="")ret+=", "; + ret+=s; + } return ret; } diff --git a/src/wext/MOCustomer.h b/src/wext/MOCustomer.h index 95a61f3..bde3b20 100644 --- a/src/wext/MOCustomer.h +++ b/src/wext/MOCustomer.h @@ -35,7 +35,7 @@ class MOCustomer:public MOCustomerAbstract QString address(int i=0); /**returns the full name (incl. title)*/ - QString fullName()const{return title()+" "+name()+", "+firstname();} + QString fullName()const; }; diff --git a/src/wext/MOCustomerInfo.cpp b/src/wext/MOCustomerInfo.cpp index 52bf13c..336d1a2 100644 --- a/src/wext/MOCustomerInfo.cpp +++ b/src/wext/MOCustomerInfo.cpp @@ -12,3 +12,18 @@ #include "MOCustomerInfo.h" +QString MOCustomerInfo::fullName()const +{ + QString ret=title().value().trimmed(); + QString s=name().value().trimmed(); + if(s!=""){ + if(ret!="")ret+=" "; + ret+=s; + } + s=firstname().value().trimmed(); + if(s!=""){ + if(ret!="")ret+=", "; + ret+=s; + } + return ret; +} diff --git a/src/wext/MOCustomerInfo.h b/src/wext/MOCustomerInfo.h index dd6c7e9..76b8900 100644 --- a/src/wext/MOCustomerInfo.h +++ b/src/wext/MOCustomerInfo.h @@ -19,7 +19,7 @@ class MOCustomerInfo:public MOCustomerInfoAbstract WOBJECT(MOCustomerInfo); public: /**returns the full name (incl. title)*/ - QString fullName()const{return title()+" "+name()+", "+firstname();} + QString fullName()const; /**alias for customerid()*/ Nullable id()const{return customerid();} diff --git a/wob/cart.wolf b/wob/cart.wolf index 641931c..426c967 100644 --- a/wob/cart.wolf +++ b/wob/cart.wolf @@ -68,6 +68,7 @@ + @@ -82,6 +83,10 @@ + + + + diff --git a/wob/customer.wolf b/wob/customer.wolf index 6b63bd5..4528a80 100644 --- a/wob/customer.wolf +++ b/wob/customer.wolf @@ -232,6 +232,10 @@ + + + + diff --git a/wob/magicsmoke.wolf b/wob/magicsmoke.wolf index d1304fc..ae08b0e 100644 --- a/wob/magicsmoke.wolf +++ b/wob/magicsmoke.wolf @@ -2,13 +2,13 @@ These files describe the database schema and communication protocol of MagicSmoke. - (c) Konrad Rosenbaum, 2009<br/>these files are protected under the GNU AGPLv3 or at your option any newer + (c) Konrad Rosenbaum, 2009-2010<br/>these files are protected under the GNU AGPLv3 or at your option any newer diff --git a/wob/order.wolf b/wob/order.wolf index bb36af6..d82b43a 100644 --- a/wob/order.wolf +++ b/wob/order.wolf @@ -410,9 +410,29 @@ - - + + CreateOrder creates orders that are queued to be executed immediately, they may contain tickets, vouchers, or shopping items + users with this privilege can create vouchers with arbitrary value + users with this privilege can create vouchers with a price (what the customer pays) different from its value (what the customer can buy with it) + + + + + + + + + + Reservations are orders that are not executed right away. They may only contain tickets that block some seats for a limited time. They cannot contain any shopping items or vouchers. + + + + + + + + This transaction turns a reservation into a regular order @@ -550,4 +570,11 @@ + + + + + + + \ No newline at end of file diff --git a/www/inc/wext/customer.php b/www/inc/wext/customer.php index 08dc8f5..9835b79 100644 --- a/www/inc/wext/customer.php +++ b/www/inc/wext/customer.php @@ -136,6 +136,65 @@ class WOCustomer extends WOCustomerAbstract //return $trans->setcustomer(WOCustomer::fromTablecustomer($ct)); } + + /**called from DeleteCustomer transaction*/ + public static function deleteCustomer($trans) + { + //get customer table objects + $dc=WTcustomer::getFromDB($trans->getcustomerid()); + $mc=WTcustomer::getFromDB($trans->getmergewithid()); + if(!is_a($dc,"WTcustomer")){ + $trans->abortWithError(tr("Not a valid customer, cannot delete.")); + return; + } + $domerge=is_a($mc,"WTcustomer"); + //delete any left over sessions + global $db; + $db->deleteRows("websession","customerid=".$db->escapeInt($dc->customerid)); + //collect owned objects + $addr=WTaddress::selectFromDB("customerid=".$db->escapeInt($dc->customerid)); + $cont=WTcontact::selectFromDB("customerid=".$db->escapeInt($dc->customerid)); + $ordr=WTorder::selectFromDB("customerid=".$db->escapeInt($dc->customerid)); + //if not merge + if(!$domerge){ + //sanity check + if(count($ordr)>0){ + $trans->abortWithError(tr("This customer has orders in the system, cannot delete.")); + return; + } + //delete sub-objects + foreach($addr as $ad) + $ad->deleteFromDB(); + foreach($cont as $ct) + $ct->deleteFromDB(); + //delete + $dc->deleteFromDB(); + }else{//if merge... + //sanity check + if($dc->customerid == $mc->customerid){ + $trans->abortWithError(tr("Cannot merge a customer with itself.")); + return; + } + //transfer sub-objects + foreach($ordr as $od){ + $od->customerid=$mc->customerid; + $od->update(); + } + foreach($cont as $od){ + $od->customerid=$mc->customerid; + $od->update(); + } + foreach($addr as $od){ + $od->customerid=$mc->customerid; + $od->update(); + } + //delete + $dc->deleteFromDB(); + //return substitute + $trans->setcustomer(WOCustomer::fromTablecustomer($mc)); + } + print($db->lastError()); + } /**called from CreateCountry transaction*/ public static function createCountry($trans)