/** * 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 11:06 AM */ package com.odoo.addons.sale; import android.content.Context; import android.database.Cursor; import android.graphics.Color; import android.os.Bundle; import android.os.Handler; import android.support.annotation.Nullable; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.support.v4.widget.SwipeRefreshLayout; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.ListView; import android.widget.Toast; import com.odoo.R; import com.odoo.addons.sale.models.SaleOrder; import com.odoo.core.orm.ODataRow; import com.odoo.core.support.addons.fragment.BaseFragment; import com.odoo.core.support.addons.fragment.IOnSearchViewChangeListener; import com.odoo.core.support.addons.fragment.ISyncStatusObserverListener; import com.odoo.core.support.drawer.ODrawerItem; import com.odoo.core.support.list.IOnItemClickListener; import com.odoo.core.support.list.OCursorListAdapter; import com.odoo.core.utils.IntentUtils; import com.odoo.core.utils.OAlert; import com.odoo.core.utils.OControls; import com.odoo.core.utils.OCursorUtils; import com.odoo.core.utils.ODateUtils; import com.odoo.core.utils.OResource; import com.odoo.core.utils.sys.IOnBackPressListener; import com.odoo.widgets.bottomsheet.BottomSheet; import com.odoo.widgets.bottomsheet.BottomSheetListeners; import java.util.ArrayList; import java.util.Arrays; import java.util.List; public class Sales extends BaseFragment implements OCursorListAdapter.OnViewBindListener, LoaderManager.LoaderCallbacks<Cursor>, SwipeRefreshLayout.OnRefreshListener, IOnSearchViewChangeListener, ISyncStatusObserverListener, IOnItemClickListener, BottomSheetListeners.OnSheetItemClickListener, BottomSheetListeners.OnSheetActionClickListener, IOnBackPressListener, View.OnClickListener { public static final String TAG = Sales.class.getSimpleName(); public static final String KEY_MENU = "key_sales_menu"; private View mView; private ListView mList; private OCursorListAdapter mAdapter; private String mFilter = null; private BottomSheet mSheet; private Type mType = Type.Quotation; private Boolean mSyncRequested = false; public enum Type { Quotation, SaleOrder } @Override public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { setHasOptionsMenu(true); mType = Type.valueOf(getArguments().getString(KEY_MENU)); return inflater.inflate(R.layout.common_listview, container, false); } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); parent().setOnBackPressListener(this); mView = view; initAdapter(); } private void initAdapter() { mList = (ListView) mView.findViewById(R.id.listview); mAdapter = new OCursorListAdapter(getActivity(), null, R.layout.sale_order_item); mAdapter.setOnViewBindListener(this); mList.setAdapter(mAdapter); mAdapter.handleItemClickListener(mList, this); setHasFloatingButton(mView, R.id.fabButton, mList, this); if (mType == Type.SaleOrder) mView.findViewById(R.id.fabButton).setVisibility(View.GONE); setHasSyncStatusObserver(TAG, this, db()); setHasSwipeRefreshView(mView, R.id.swipe_container, this); getLoaderManager().initLoader(0, null, this); } @Override public void onViewBind(View view, Cursor cursor, ODataRow row) { OControls.setText(view, R.id.name, row.getString("name")); String format = (db().getUser().getVersion_number() <= 7) ? ODateUtils.DEFAULT_DATE_FORMAT : ODateUtils.DEFAULT_FORMAT; String date = ODateUtils.convertToDefault(row.getString("date_order"), format, "MMMM, dd"); OControls.setText(view, R.id.date_order, date); OControls.setText(view, R.id.state, row.getString("state_title")); if (row.getString("partner_name").equals("false")) { OControls.setGone(view, (R.id.partner_name)); } else { OControls.setVisible(view, R.id.partner_name); OControls.setText(view, R.id.partner_name, row.getString("partner_name")); } OControls.setText(view, R.id.amount_total, row.getString("amount_total")); if (row.getString("currency_symbol").equals("false")) { OControls.setGone(view, (R.id.currency_symbol)); } else { OControls.setVisible(view, R.id.currency_symbol); OControls.setText(view, R.id.currency_symbol, row.getString("currency_symbol")); } OControls.setText(view, R.id.order_lines, row.getString("order_line_count")); } @Override public List<ODrawerItem> drawerMenus(Context context) { List<ODrawerItem> menu = new ArrayList<>(); menu.add(new ODrawerItem(TAG).setTitle(OResource.string(context, R.string.label_quotation)) .setIcon(R.drawable.ic_action_quotation) .setInstance(new Sales()) .setExtra(data(Type.Quotation))); menu.add(new ODrawerItem(TAG).setTitle(OResource.string(context, R.string.label_sale_orders)) .setIcon(R.drawable.ic_action_sale_order) .setInstance(new Sales()) .setExtra(data(Type.SaleOrder))); return menu; } @Override public Loader<Cursor> onCreateLoader(int id, Bundle data) { String where = null; String[] whereArgs = null; List<String> args = new ArrayList<>(); switch (mType) { case Quotation: where = " (state = ? or state = ?)"; args.addAll(Arrays.asList(new String[]{"draft", "cancel"})); break; case SaleOrder: where = "(state = ? or state = ? or state = ?)"; args.addAll(Arrays.asList(new String[]{"manual", "progress", "done"})); break; } if (mFilter != null) { where += " and (name like ? or partner_name like ? or state_title like ?)"; args.add("%" + mFilter + "%"); args.add("%" + mFilter + "%"); args.add("%" + mFilter + "%"); } whereArgs = args.toArray(new String[args.size()]); return new CursorLoader(getActivity(), db().uri(), null, where, whereArgs, "date_order DESC"); } @Override public void onLoadFinished(Loader<Cursor> loader, Cursor data) { mAdapter.changeCursor(data); if (data.getCount() > 0) { new Handler().postDelayed(new Runnable() { @Override public void run() { OControls.setGone(mView, R.id.loadingProgress); OControls.setVisible(mView, R.id.swipe_container); OControls.setGone(mView, R.id.customer_no_items); setHasSwipeRefreshView(mView, R.id.swipe_container, Sales.this); } }, 500); } else { if (db().isEmptyTable() && !mSyncRequested) { mSyncRequested = true; onRefresh(); } new Handler().postDelayed(new Runnable() { @Override public void run() { OControls.setGone(mView, R.id.loadingProgress); OControls.setGone(mView, R.id.swipe_container); OControls.setVisible(mView, R.id.customer_no_items); setHasSwipeRefreshView(mView, R.id.customer_no_items, Sales.this); OControls.setImage(mView, R.id.icon, (mType == Type.Quotation) ? R.drawable.ic_action_quotation : R.drawable.ic_action_sale_order); OControls.setText(mView, R.id.title, "No " + mType + " Found"); OControls.setText(mView, R.id.subTitle, ""); } }, 500); } } @Override public void onLoaderReset(Loader<Cursor> loader) { mAdapter.changeCursor(null); } private Bundle data(Type type) { Bundle extra = new Bundle(); extra.putString(KEY_MENU, type.toString()); return extra; } @Override public Class<SaleOrder> database() { return SaleOrder.class; } @Override public void onRefresh() { if (inNetwork()) { parent().sync().requestSync(SaleOrder.AUTHORITY); setSwipeRefreshing(true); } else { hideRefreshingProgress(); Toast.makeText(getActivity(), _s(R.string.toast_network_required), Toast.LENGTH_LONG) .show(); } } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); menu.clear(); inflater.inflate(R.menu.menu_sales_order, menu); setHasSearchView(this, menu, R.id.menu_sales_search); } @Override public boolean onSearchViewTextChange(String newFilter) { mFilter = newFilter; getLoaderManager().restartLoader(0, null, this); return true; } @Override public void onSearchViewClose() { //Nothing to do } @Override public void onStatusChange(Boolean refreshing) { getLoaderManager().restartLoader(0, null, this); } @Override public void onItemDoubleClick(View view, int position) { onDoubleClick(position); } private void onDoubleClick(int position) { ODataRow row = OCursorUtils.toDatarow((Cursor) mAdapter.getItem(position)); Bundle data = row.getPrimaryBundleData(); data.putString("type", mType.toString()); IntentUtils.startActivity(getActivity(), SalesDetail.class, data); } @Override public void onItemClick(View view, int position) { if (mType == Type.Quotation) showSheet((Cursor) mAdapter.getItem(position)); else onDoubleClick(position); } private void showSheet(Cursor data) { BottomSheet.Builder builder = new BottomSheet.Builder(getActivity()); builder.listener(this); builder.setIconColor(_c(R.color.theme_primary_dark)); builder.setTextColor(Color.parseColor("#414141")); builder.setData(data); builder.actionListener(this); builder.setActionIcon(R.drawable.ic_action_edit); builder.title(data.getString(data.getColumnIndex("name"))); if (data.getString(data.getColumnIndex("state")).equals("cancel")) builder.menu(R.menu.menu_quotation_cancel_sheet); else builder.menu(R.menu.menu_quotation_sheet); mSheet = builder.create(); mSheet.show(); } @Override public void onItemClick(BottomSheet sheet, MenuItem menu, Object extras) { mSheet.dismiss(); ODataRow row = OCursorUtils.toDatarow((Cursor) extras); switch (menu.getItemId()) { // case R.id.menu_so_send_by_email: // break; case R.id.menu_quotation_cancel: ((SaleOrder) db()).cancelOrder(mType, row, cancelOrder); break; case R.id.menu_quotation_new: if (inNetwork()) { ((SaleOrder) db()).newCopyQuotation(row, newCopyQuotation); } else { Toast.makeText(getActivity(), R.string.toast_network_required, Toast.LENGTH_LONG).show(); } break; case R.id.menu_so_confirm_sale: if (row.getFloat("amount_total") > 0) { if (inNetwork()) { ((SaleOrder) db()).confirmSale(row, confirmSale); } else { Toast.makeText(getActivity(), R.string.toast_network_required, Toast.LENGTH_LONG).show(); } } else { OAlert.showWarning(getActivity(), "You cannot a sales order which has no line"); } break; } } SaleOrder.OnOperationSuccessListener cancelOrder = new SaleOrder.OnOperationSuccessListener() { @Override public void OnSuccess() { Toast.makeText(getActivity(), mType + " cancelled", Toast.LENGTH_LONG).show(); } @Override public void OnCancelled() { } }; SaleOrder.OnOperationSuccessListener confirmSale = new SaleOrder.OnOperationSuccessListener() { @Override public void OnSuccess() { Toast.makeText(getActivity(), "Quotation confirmed !", Toast.LENGTH_LONG).show(); } @Override public void OnCancelled() { } }; SaleOrder.OnOperationSuccessListener newCopyQuotation = new SaleOrder.OnOperationSuccessListener() { @Override public void OnSuccess() { Toast.makeText(getActivity(), R.string.label_copy_quotation, Toast.LENGTH_LONG).show(); } @Override public void OnCancelled() { } }; @Override public void onSheetActionClick(BottomSheet sheet, Object extras) { mSheet.dismiss(); ODataRow row = OCursorUtils.toDatarow((Cursor) extras); Bundle data = row.getPrimaryBundleData(); data.putString("type", mType.toString()); IntentUtils.startActivity(getActivity(), SalesDetail.class, data); } @Override public boolean onBackPressed() { if (mSheet != null && mSheet.isShowing()) { mSheet.dismiss(); return false; } return true; } @Override public void onClick(View v) { switch (v.getId()) { case R.id.fabButton: Bundle bundle = new Bundle(); bundle.putString("type", Type.Quotation.toString()); IntentUtils.startActivity(getActivity(), SalesDetail.class, bundle); break; } } }