/**
* Odoo, Open Source Management Solution
* Copyright (C) 2012-today Odoo SA (<http:www.odoo.com>)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http:www.gnu.org/licenses/>
*
* Created on 13/1/15 5:09 PM
*/
package com.odoo.addons.sale;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.odoo.App;
import com.odoo.R;
import com.odoo.addons.sale.models.ProductProduct;
import com.odoo.addons.sale.models.SaleOrder;
import com.odoo.addons.sale.models.SalesOrderLine;
import com.odoo.base.addons.res.ResPartner;
import com.odoo.core.orm.ODataRow;
import com.odoo.core.orm.OValues;
import com.odoo.core.orm.ServerDataHelper;
import com.odoo.core.orm.fields.OColumn;
import com.odoo.core.utils.JSONUtils;
import com.odoo.core.utils.OActionBarUtils;
import com.odoo.core.utils.OAlert;
import com.odoo.core.utils.OControls;
import com.odoo.core.utils.OResource;
import com.odoo.core.utils.StringUtils;
import org.json.JSONArray;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import odoo.OArguments;
import odoo.controls.ExpandableListControl;
import odoo.controls.OField;
import odoo.controls.OForm;
import static com.odoo.addons.sale.Sales.Type;
public class SalesDetail extends ActionBarActivity implements View.OnClickListener {
public static final String TAG = SalesDetail.class.getSimpleName();
public static final int REQUEST_ADD_ITEMS = 323;
private Bundle extra;
private OForm mForm;
private ODataRow record;
private SaleOrder sale;
private ActionBar actionBar;
private ExpandableListControl mList;
private ExpandableListControl.ExpandableListAdapter mAdapter;
private List<Object> objects = new ArrayList<>();
private HashMap<String, Float> lineValues = new HashMap<>();
private HashMap<String, Integer> lineIds = new HashMap<>();
private TextView txvType, currency1, currency2, currency3, untaxedAmt, taxesAmt, total_amt;
private ODataRow currencyObj;
private ResPartner partner = null;
private ProductProduct products = null;
private String mSOType = "";
private LinearLayout layoutAddItem = null;
private Type mType;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.sale_detail);
OActionBarUtils.setActionBar(this, true);
actionBar = getSupportActionBar();
sale = new SaleOrder(this, null);
extra = getIntent().getExtras();
mType = Type.valueOf(extra.getString("type"));
currencyObj = sale.currency();
partner = new ResPartner(this, null);
products = new ProductProduct(this, null);
init();
initAdapter();
}
private void init() {
mForm = (OForm) findViewById(R.id.saleForm);
mForm.setEditable(true);
txvType = (TextView) findViewById(R.id.txvType);
currency1 = (TextView) findViewById(R.id.currency1);
currency2 = (TextView) findViewById(R.id.currency2);
currency3 = (TextView) findViewById(R.id.currency3);
String currencySymbol = currencyObj.getString("symbol");
untaxedAmt = (TextView) findViewById(R.id.untaxedTotal);
taxesAmt = (TextView) findViewById(R.id.taxesTotal);
total_amt = (TextView) findViewById(R.id.fTotal);
untaxedAmt.setText("0.00");
taxesAmt.setText("0.00");
total_amt.setText("0.00");
layoutAddItem = (LinearLayout) findViewById(R.id.layoutAddItem);
layoutAddItem.setOnClickListener(this);
if (extra == null || !extra.containsKey(OColumn.ROW_ID)) {
mForm.initForm(null);
actionBar.setTitle(R.string.label_new);
actionBar.setHomeAsUpIndicator(R.drawable.ic_action_navigation_close);
txvType.setText(R.string.label_quotation);
} else {
record = sale.browse(extra.getInt(OColumn.ROW_ID));
if (record == null) {
finish();
}
if (!record.getString("partner_id").equals("false") && mType == Type.Quotation) {
OnCustomerChangeUpdate onCustomerChangeUpdate = new OnCustomerChangeUpdate();
onCustomerChangeUpdate.execute(record.getM2ORecord("partner_id").browse());
}
if (mType == Type.Quotation) {
actionBar.setTitle(R.string.label_quotation);
txvType.setText(R.string.label_quotation);
if (record.getString("state").equals("cancel"))
layoutAddItem.setVisibility(View.GONE);
} else {
layoutAddItem.setVisibility(View.GONE);
actionBar.setTitle(R.string.label_sale_orders);
txvType.setText(R.string.label_sale_orders);
mForm.setEditable(false);
}
currencySymbol = record.getM2ORecord("currency_id").browse().getString("symbol");
untaxedAmt.setText(String.format("%.2f", record.getFloat("amount_untaxed")));
taxesAmt.setText(String.format("%.2f", record.getFloat("amount_tax")));
total_amt.setText(String.format("%.2f", record.getFloat("amount_total")));
mForm.initForm(record);
}
mSOType = txvType.getText().toString();
currency1.setText(currencySymbol);
currency2.setText(currencySymbol);
currency3.setText(currencySymbol);
}
private void initAdapter() {
mList = (ExpandableListControl) findViewById(R.id.expListOrderLine);
mList.setVisibility(View.VISIBLE);
if (extra != null && record != null) {
List<ODataRow> lines = record.getO2MRecord("order_line").browseEach();
for (ODataRow line : lines) {
int product_id = products.selectServerId(line.getInt("product_id"));
if (product_id != 0) {
lineValues.put(product_id + "", line.getFloat("product_uom_qty"));
lineIds.put(product_id + "", line.getInt("id"));
}
}
objects.addAll(lines);
}
mAdapter = mList.getAdapter(R.layout.sale_order_line_item, objects,
new ExpandableListControl.ExpandableListAdapterGetViewListener() {
@Override
public View getView(int position, View mView, ViewGroup parent) {
ODataRow row = (ODataRow) mAdapter.getItem(position);
OControls.setText(mView, R.id.edtName, row.getString("name"));
OControls.setText(mView, R.id.edtProductQty, row.getString("product_uom_qty"));
OControls.setText(mView, R.id.edtProductPrice, String.format("%.2f", row.getFloat("price_unit")));
OControls.setText(mView, R.id.edtSubTotal, String.format("%.2f", row.getFloat("price_subtotal")));
return mView;
}
});
mAdapter.notifyDataSetChanged(objects);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_sale_detail, menu);
OField name = (OField) mForm.findViewById(R.id.fname);
name.setEditable(false);
if (extra != null && !extra.getString("type").equals(Type.SaleOrder.toString())) {
// Operation on Sale Order
} else {
menu.findItem(R.id.menu_sale_save).setVisible(false);
menu.findItem(R.id.menu_sale_confirm_sale).setVisible(false);
}
if (extra != null && record != null && record.getString("state").equals("cancel")) {
menu.findItem(R.id.menu_sale_save).setVisible(true).setTitle("Copy Quotation");
menu.findItem(R.id.menu_sale_detail_more).setVisible(false);
mForm.setEditable(true);
} else {
menu.findItem(R.id.menu_sale_detail_more).setVisible(false);
menu.findItem(R.id.menu_sale_new_copy_of_quotation).setVisible(false);
}
if (extra == null || !extra.containsKey(OColumn.ROW_ID)) {
menu.findItem(R.id.menu_sale_save).setVisible(true);
menu.findItem(R.id.menu_sale_detail_more).setVisible(false);
}
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
OValues values = mForm.getValues();
App app = (App) getApplicationContext();
switch (item.getItemId()) {
case android.R.id.home:
finish();
break;
case R.id.menu_sale_save:
if (values != null) {
if (app.inNetwork()) {
values.put("partner_name", partner.getName(values.getInt("partner_id")));
SaleOrderOperation saleOrderOperation = new SaleOrderOperation();
saleOrderOperation.execute(values);
} else {
Toast.makeText(this, R.string.toast_network_required, Toast.LENGTH_LONG).show();
}
}
break;
case R.id.menu_sale_confirm_sale:
if (record != null) {
if (extra != null && record.getFloat("amount_total") > 0) {
if (app.inNetwork()) {
sale.confirmSale(record, confirmSale);
} else {
Toast.makeText(this, R.string.toast_network_required, Toast.LENGTH_LONG).show();
}
} else {
OAlert.showWarning(this, R.string.label_no_order_line + "");
}
}
break;
}
return super.onOptionsItemSelected(item);
}
private class SaleOrderOperation extends AsyncTask<OValues, Void, Boolean> {
private ProgressDialog mDialog;
@Override
protected void onPreExecute() {
super.onPreExecute();
mDialog = new ProgressDialog(SalesDetail.this);
mDialog.setTitle(R.string.title_working);
mDialog.setMessage("Creating lines");
mDialog.setCancelable(false);
mDialog.show();
}
@Override
protected Boolean doInBackground(OValues... params) {
try {
Thread.sleep(500);
OValues values = params[0];
// Creating oneToMany order lines
JSONArray order_line = new JSONArray();
for (Object line : objects) {
JSONArray o_line = new JSONArray();
ODataRow row = (ODataRow) line;
String product_id = row.getString("product_id");
o_line.put((lineIds.containsKey(product_id)) ? 1 : 0);
o_line.put((lineIds.containsKey(product_id)) ? lineIds.get(product_id) : false);
if (lineIds.containsKey(product_id)) {
JSONObject line_data = new JSONObject();
line_data.put("product_uom_qty", row.get("product_uom_qty"));
line_data.put("product_uos_qty", row.get("product_uos_qty"));
o_line.put(line_data);
} else
o_line.put(JSONUtils.toJSONObject(row));
order_line.put(o_line);
lineIds.remove(product_id);
}
if (lineIds.size() > 0) {
for (String key : lineIds.keySet()) {
JSONArray o_line = new JSONArray();
o_line.put(2);
o_line.put(lineIds.get(key));
o_line.put(false);
order_line.put(o_line);
}
}
Thread.sleep(500);
JSONObject data = new JSONObject();
data.put("name", values.getString("name"));
data.put("partner_id", partner.selectServerId(values.getInt("partner_id")));
data.put("date_order", values.getString("date_order"));
data.put("payment_term", values.get("payment_term"));
data.put("order_line", order_line);
if (record == null) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mDialog.setMessage("Creating " + mSOType);
}
});
Thread.sleep(500);
int new_id = sale.getServerDataHelper().createOnServer(data);
values.put("id", new_id);
ODataRow record = new ODataRow();
record.put("id", new_id);
sale.quickCreateRecord(record);
//sale.insert(values);
} else {
runOnUiThread(new Runnable() {
@Override
public void run() {
mDialog.setMessage("Updating " + mSOType);
}
});
Thread.sleep(500);
sale.getServerDataHelper().updateOnServer(data, record.getInt("id"));
sale.quickCreateRecord(record);
}
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
@Override
protected void onPostExecute(Boolean success) {
super.onPostExecute(success);
mDialog.dismiss();
if (success) {
Toast.makeText(SalesDetail.this, (record != null) ? mSOType + " updated"
: mSOType + " created", Toast.LENGTH_LONG).show();
finish();
}
}
}
SaleOrder.OnOperationSuccessListener cancelOrder = new SaleOrder.OnOperationSuccessListener() {
@Override
public void OnSuccess() {
Toast.makeText(SalesDetail.this, StringUtils.capitalizeString(extra.getString("type"))
+ " cancelled", Toast.LENGTH_LONG).show();
finish();
}
@Override
public void OnCancelled() {
}
};
SaleOrder.OnOperationSuccessListener confirmSale = new SaleOrder.OnOperationSuccessListener() {
@Override
public void OnSuccess() {
Toast.makeText(SalesDetail.this, R.string.label_quotation_confirm, Toast.LENGTH_LONG).show();
finish();
}
@Override
public void OnCancelled() {
}
};
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.layoutAddItem:
if (mForm.getValues() != null) {
Intent intent = new Intent(this, AddProductLineWizard.class);
Bundle extra = new Bundle();
for (String key : lineValues.keySet()) {
extra.putFloat(key, lineValues.get(key));
}
intent.putExtras(extra);
startActivityForResult(intent, REQUEST_ADD_ITEMS);
}
break;
}
}
private class OnCustomerChangeUpdate extends AsyncTask<ODataRow, Void, Void> {
private ProgressDialog progressDialog;
@Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = new ProgressDialog(SalesDetail.this);
progressDialog.setCancelable(false);
progressDialog.setTitle(R.string.title_please_wait);
progressDialog.setMessage(OResource.string(SalesDetail.this, R.string.title_working));
progressDialog.show();
}
@Override
protected Void doInBackground(ODataRow... params) {
sale.onPartnerIdChange(params[0]);
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
progressDialog.dismiss();
}
}
private class OnProductChange extends AsyncTask<HashMap<String, Float>, Void, List<ODataRow>> {
private ProgressDialog progressDialog;
private String warning = null;
@Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog = new ProgressDialog(SalesDetail.this);
progressDialog.setCancelable(false);
progressDialog.setTitle(R.string.title_please_wait);
progressDialog.setMessage(OResource.string(SalesDetail.this, R.string.title_working));
progressDialog.show();
}
@Override
protected List<ODataRow> doInBackground(HashMap<String, Float>... params) {
List<ODataRow> items = new ArrayList<>();
try {
ProductProduct productProduct = new ProductProduct(SalesDetail.this, sale.getUser());
SalesOrderLine saleLine = new SalesOrderLine(SalesDetail.this, sale.getUser());
ResPartner partner = new ResPartner(SalesDetail.this, sale.getUser());
ODataRow customer = partner.browse(mForm.getValues().getInt("partner_id"));
ServerDataHelper helper = saleLine.getServerDataHelper();
boolean stockInstalled = saleLine.isInstalledOnServer("stock");
for (String key : params[0].keySet()) {
ODataRow product = productProduct.browse(productProduct.selectRowId(Integer.parseInt(key)));
Float qty = params[0].get(key);
OArguments arguments = new OArguments();
arguments.add(new JSONArray());
int pricelist = customer.getInt("pricelist_id");
arguments.add(pricelist); // Price List for customer
arguments.add(product.getInt("id")); // product id
arguments.add(qty); // Quantity
arguments.add(false); // UOM
arguments.add(qty); // Qty_UOS
arguments.add(false);// UOS
arguments.add((product.getString("name").equals("false")) ? false
: product.getString("name"));
arguments.add(customer.getInt("id")); // Partner id
arguments.add(false); // lang
arguments.add(true); // update_tax
arguments.add((customer.getString("date_order").equals("false")) ? false
: customer.getString("date_order")); // date order
arguments.add(false); // packaging
Object fiscal_position = (customer.getString("fiscal_position").equals("false"))
? false : customer.getString("fiscal_position");
arguments.add(fiscal_position);// fiscal position
arguments.add(false); // flag
int version = saleLine.getOdooVersion().getVersion_number();
if (stockInstalled && version > 7) {
arguments.add(false);
}
JSONObject context = new JSONObject();
context.put("partner_id", customer.getInt("id"));
context.put("quantity", qty);
context.put("pricelist", pricelist);
// Fixed for Odoo 7.0 no product_id_change_with_wh available for v7
String method = (stockInstalled && version > 7) ? "product_id_change_with_wh" : "product_id_change";
JSONObject response = ((JSONObject) helper.callMethod(method, arguments, context));
JSONObject res = response.getJSONObject("value");
if (response.has("warning") && !response.getString("warning").equals("false")) {
JSONObject warning_data = response.getJSONObject("warning");
if (warning_data.has("message"))
warning = warning_data.getString("message");
}
OValues values = new OValues();
values.put("product_id", product.getInt("id"));
values.put("name", res.get("name"));
values.put("product_uom_qty", res.get("product_uos_qty"));
values.put("product_uom", res.get("product_uom"));
values.put("price_unit", res.get("price_unit"));
values.put("product_uos_qty", res.getDouble("product_uos_qty"));
values.put("product_uos", false);
values.put("price_subtotal", res.getDouble("price_unit") * res.getDouble("product_uos_qty"));
JSONArray tax_id = new JSONArray();
tax_id.put(6);
tax_id.put(false);
tax_id.put(res.getJSONArray("tax_id"));
values.put("tax_id", new JSONArray().put(tax_id));
values.put("th_weight", (res.has("th_weight")) ? res.get("th_weight") : 0);
values.put("discount", (res.has("discount")) ? res.get("discount") : 0);
if (stockInstalled) {
values.put("route_id", (res.has("route_id")) ? res.get("route_id") : false);
values.put("delay", res.get("delay"));
}
if (extra != null)
values.put("order_id", extra.getInt(OColumn.ROW_ID));
items.add(values.toDataRow());
}
} catch (Exception e) {
e.printStackTrace();
}
return items;
}
@Override
protected void onPostExecute(List<ODataRow> row) {
super.onPostExecute(row);
if (row != null) {
objects.clear();
objects.addAll(row);
mAdapter.notifyDataSetChanged(objects);
float total = 0.0f;
for (ODataRow rec : row) {
total += rec.getFloat("price_subtotal");
}
total_amt.setText(String.format("%.2f", total));
untaxedAmt.setText(total_amt.getText());
}
progressDialog.dismiss();
if (warning != null) {
OAlert.showWarning(SalesDetail.this, warning.trim());
}
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_ADD_ITEMS && resultCode == Activity.RESULT_OK) {
lineValues.clear();
for (String key : data.getExtras().keySet()) {
if (data.getExtras().getFloat(key) > 0)
lineValues.put(key, data.getExtras().getFloat(key));
}
OnProductChange onProductChange = new OnProductChange();
onProductChange.execute(lineValues);
}
}
}