├── README.md ├── adater └── FBCustomerDialogAdapter.kt ├── app └── AppController.kt ├── db ├── AndroidDatabase.kt ├── Database.kt ├── DatabaseContents.kt ├── DatabaseExecutor.kt ├── Demo.kt ├── NoDaoSetException.kt ├── Tax │ ├── Tax.kt │ ├── TaxDao.kt │ ├── TaxDbo.kt │ └── tax_model.kt ├── customer │ ├── CustomerDao.kt │ └── CustomerDbao.kt ├── inventory │ ├── CategoryDao.kt │ ├── CategoryDbo.kt │ ├── InventoryDao.kt │ └── InventoryDaoAndroid.kt └── sale │ ├── SaleDao.kt │ └── SaleDaoAndroid.kt ├── domain ├── DateTimeStrategy.kt ├── LanguageController.kt ├── inventory │ ├── Category.kt │ ├── Inventory.kt │ ├── LineItem.kt │ ├── Product.kt │ ├── ProductCatalog.kt │ ├── ProductLot.kt │ └── Stock.kt └── sale │ ├── QuickLoadSale.java │ ├── Register.kt │ ├── Sale.kt │ ├── SaleLedger.kt │ └── SalesRcord.kt ├── mcposprivacy.html ├── print ├── MainActivityPrint.kt └── UnicodeFormatter.java ├── settings ├── AppCompatPreferenceActivity.java ├── MainSettingsActivity.java └── SettingsActivity.java ├── ui ├── MainActivity.kt ├── SplashScreenActivity.kt ├── component │ ├── ButtonAdapter.kt │ └── UpdatableFragment.kt ├── inventory │ ├── AddProductDialogFragment.kt │ ├── CilckCallBack.kt │ ├── InventeryProductAdapter.kt │ ├── InventoryFragment.kt │ └── ProductDetailActivity.kt ├── sale │ ├── ActivityMainMenu.kt │ ├── ActivitySalesRecord.kt │ ├── EditFragmentDialog.kt │ ├── EndPaymentFragmentDialog.kt │ ├── PaymentFragment.kt │ ├── PaymentFragmentDialog.kt │ ├── ReportFragment.kt │ ├── SaleDetailActivity.kt │ ├── SaleFragment.kt │ ├── SalesProductAdapter.kt │ ├── adapter │ │ ├── CategoryAdapter.kt │ │ └── SalesRcordRecyclerViewAdapter.kt │ └── model │ │ ├── CategoryModel.kt │ │ ├── CustomerModel.kt │ │ ├── PriceListModel.kt │ │ ├── SalesRecordModel.kt │ │ └── SalesTypes.java └── view │ └── GridRecyclerView.java └── utils ├── CircleTransform.java ├── Constance.kt ├── FBCustomerDialog.kt ├── FBDatePickerFragment.kt ├── IONPreferences.kt ├── IconMenuAdapter.kt ├── ListViewCallback.java └── RecordStatus.kt /README.md: -------------------------------------------------------------------------------- 1 | # Android POS 2 | Android based pos application , customized for ERP , Fully OOD kotlin ,you can dowload full android pos source code from the website http://www.mycodlabs.com/android-pos-source-code-download 3 | -------------------------------------------------------------------------------- /adater/FBCustomerDialogAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.fitbae.fitness.adapter 2 | 3 | import android.app.Activity 4 | import android.content.Context 5 | import android.media.ImageReader 6 | import android.view.View 7 | import android.view.ViewGroup 8 | import android.widget.BaseAdapter 9 | import android.widget.TextView 10 | import com.ionob.pos.R 11 | import com.ionob.pos.ui.sale.model.CustomerModel 12 | import java.util.* 13 | import kotlin.collections.ArrayList 14 | 15 | class FBCustomerDialogAdapter(private val customers: ArrayList, 16 | private val context: Context) : BaseAdapter() { 17 | private var searchedData: ArrayList? = null 18 | private var onItemSelectedListner: OnItemSelected? = null 19 | 20 | init { 21 | searchedData = ArrayList() 22 | searchedData!!.addAll(customers) 23 | } 24 | 25 | override fun getCount(): Int { 26 | return customers.size 27 | } 28 | 29 | override fun getItem(position: Int): CustomerModel { 30 | return customers[position] 31 | } 32 | 33 | 34 | override fun getItemId(position: Int): Long { 35 | return position.toLong() 36 | } 37 | 38 | override fun getView(position: Int, view: View?, viewGroup: ViewGroup): View { 39 | var convertView = view 40 | val holder: ViewHolder 41 | val inflater = (context as Activity).layoutInflater 42 | val data = customers[position] 43 | if (convertView == null) { 44 | convertView = inflater.inflate(R.layout.adapter_customer_search, null) 45 | holder = ViewHolder(convertView!!) 46 | convertView.tag = holder 47 | } else { 48 | holder = convertView.tag as ViewHolder 49 | } 50 | // holder.customerName.tag = position 51 | // holder.countryCodeText.tag = position 52 | 53 | holder.customerName.text=data.customerName 54 | holder.customerAddress.text=data.address1 55 | holder.customerPhoneNumebr.text=data.phone 56 | holder.customerEmail.text=data.email 57 | holder.view.setOnClickListener { 58 | onItemSelectedListner!!.onItemSelected(data) 59 | } 60 | 61 | 62 | return convertView 63 | } 64 | 65 | internal inner class ViewHolder(itemView: View) { 66 | var view = itemView 67 | var customerName: TextView = itemView.findViewById(R.id.customer_name) as TextView 68 | var customerAddress: TextView = itemView.findViewById(R.id.customer_address) as TextView 69 | var customerPhoneNumebr: TextView = itemView.findViewById(R.id.customer_phone) as TextView 70 | var customerEmail: TextView = itemView.findViewById(R.id.customer_email) as TextView 71 | } 72 | 73 | fun setListner(onItemSelectlistner: OnItemSelected?) { 74 | this.onItemSelectedListner = onItemSelectlistner 75 | } 76 | 77 | interface OnItemSelected { 78 | fun onItemSelected(selectedCustomer: CustomerModel) 79 | } 80 | 81 | // Filter Class 82 | fun filter(charText: String) { 83 | val searchWord = charText.toLowerCase(Locale.getDefault()) 84 | customers.clear() 85 | if (searchWord.isEmpty()) { 86 | customers.addAll(searchedData!!) 87 | } else { 88 | for (wp in searchedData!!) { 89 | if (wp.customerName!!.toLowerCase(Locale.getDefault()).contains(charText.toLowerCase(Locale.getDefault())) 90 | || wp.customerCode!!.toLowerCase(Locale.getDefault()).contains(charText.toLowerCase(Locale.getDefault()))) { 91 | customers.add(wp) 92 | } 93 | } 94 | } 95 | notifyDataSetChanged() 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /app/AppController.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.app 2 | 3 | import android.preference.Preference 4 | import android.support.multidex.MultiDexApplication 5 | import com.ionob.pos.db.AndroidDatabase 6 | import com.ionob.pos.ui.sale.model.CustomerModel 7 | 8 | import java.util.Date 9 | 10 | 11 | class AppController : MultiDexApplication() { 12 | 13 | private val TAG = javaClass.simpleName 14 | 15 | val dbPath: String 16 | get() = getDatabasePath(AndroidDatabase.DATABASE_NAME).path 17 | 18 | fun getSelectedSalesRep(): CustomerModel? { 19 | 20 | return null 21 | } 22 | 23 | fun setSelectedSalsesRep(salesRep: CustomerModel) { 24 | //Preference.setSelectedProfile(selectedProfile.getId()) 25 | } 26 | 27 | 28 | override fun onCreate() { 29 | super.onCreate() 30 | instance = this 31 | } 32 | 33 | 34 | 35 | companion object { 36 | @get:Synchronized 37 | var instance: AppController? = null 38 | 39 | 40 | } 41 | 42 | } 43 | 44 | -------------------------------------------------------------------------------- /db/Database.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.db 2 | 3 | /** 4 | * Interface of CRUD operation. 5 | * 6 | * @author Ionob Team 7 | */ 8 | interface Database { 9 | 10 | /** 11 | * Selects something in database. 12 | * @param queryString query string for select in database. 13 | * @return list of object. 14 | */ 15 | fun select(queryString: String): List? 16 | 17 | /** 18 | * Inserts something in database. 19 | * @param tableName name of table in database. 20 | * @param content string for using in database. 21 | * @return id of row data. 22 | */ 23 | fun insert(tableName: String, content: Any): Int 24 | 25 | /** 26 | * Updates something in database. 27 | * @param tableName name of table in database. 28 | * @param content string for using in database. 29 | * @return true if updates success ; otherwise false. 30 | */ 31 | fun update(tableName: String, content: Any): Boolean 32 | 33 | 34 | /** 35 | * Updates something in database. 36 | * @param tableName name of table in database. 37 | * @param content string for using in database. 38 | * @return true if updates success ; otherwise false. 39 | */ 40 | fun updateStock(tableName: String, content: Any): Boolean 41 | 42 | 43 | /** 44 | * Deletes something in database. 45 | * @param tableName name of table in database. 46 | * @param id a specific id of row data for deletion. 47 | * @return true if deletion success ; otherwise false. 48 | */ 49 | fun delete(tableName: String, id: Int): Boolean 50 | 51 | /** 52 | * Directly execute to database. 53 | * @param queryString query string for execute. 54 | * @return true if executes success ; otherwise false. 55 | */ 56 | fun execute(queryString: String): Boolean 57 | } 58 | -------------------------------------------------------------------------------- /db/DatabaseContents.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.db 2 | 3 | /** 4 | * Enum for name of tables in database. 5 | * 6 | * @author Ionob Team 7 | */ 8 | enum class DatabaseContents 9 | /** 10 | * Constructs DatabaseContents. 11 | * @param name name of this content for using in database. 12 | */ 13 | private constructor(val nam: String?) { 14 | 15 | DATABASE("com.refresh.db1"), 16 | TABLE_PRODUCT_CATALOG("product_catalog"), 17 | TABLE_PRODUCT_CATEGORY("category"), 18 | TABLE_STOCK("stock"), 19 | TABLE_SALE("sale"), 20 | TABLE_SALE_LINEITEM("sale_lineitem"), 21 | TABLE_STOCK_SUM("stock_sum"), 22 | LANGUAGE("language"), 23 | TABLE_CUSTOMER("customer"), 24 | TABLE_TAX("tax"); 25 | 26 | override fun toString(): String { 27 | return nam!! 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /db/DatabaseExecutor.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.db 2 | 3 | /** 4 | * Uses to directly access to database. 5 | * 6 | * @author Ionob Team 7 | */ 8 | class DatabaseExecutor private constructor() { 9 | 10 | /** 11 | * Drops all data in database. 12 | */ 13 | fun dropAllData() { 14 | execute("DELETE FROM " + DatabaseContents.TABLE_PRODUCT_CATALOG + ";") 15 | execute("DELETE FROM " + DatabaseContents.TABLE_SALE + ";") 16 | execute("DELETE FROM " + DatabaseContents.TABLE_SALE_LINEITEM + ";") 17 | execute("DELETE FROM " + DatabaseContents.TABLE_STOCK + ";") 18 | execute("DELETE FROM " + DatabaseContents.TABLE_STOCK_SUM + ";") 19 | execute("VACUUM;") 20 | } 21 | 22 | /** 23 | * Directly execute to database. 24 | * @param queryString query string for execute. 25 | */ 26 | private fun execute(queryString: String) { 27 | database!!.execute(queryString) 28 | } 29 | 30 | companion object { 31 | 32 | private var database: Database? = null 33 | private var instance: DatabaseExecutor? = null 34 | 35 | /** 36 | * Sets database for use in DatabaseExecutor. 37 | * @param db database. 38 | */ 39 | internal fun setDatabase(db: Database) { 40 | database = db 41 | } 42 | 43 | internal fun getInstance(): DatabaseExecutor { 44 | if (instance == null) 45 | instance = DatabaseExecutor() 46 | return instance as DatabaseExecutor 47 | } 48 | } 49 | 50 | 51 | } 52 | -------------------------------------------------------------------------------- /db/Demo.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.db 2 | 3 | import android.app.Application 4 | import java.io.BufferedReader 5 | import java.io.InputStreamReader 6 | 7 | import android.content.Context 8 | import android.provider.Telephony 9 | import android.util.Log 10 | 11 | import com.ionob.pos.R 12 | import com.ionob.pos.db.Tax.Tax 13 | import com.ionob.pos.db.Tax.TaxDbo 14 | import com.ionob.pos.db.customer.CustomerDbao 15 | import com.ionob.pos.db.inventory.CategoryDbo 16 | import com.ionob.pos.domain.inventory.Category 17 | import com.ionob.pos.domain.inventory.Inventory 18 | import com.ionob.pos.ui.sale.model.CustomerModel 19 | import java.math.BigDecimal 20 | 21 | /** 22 | * Reads a demo products from CSV in res/raw/ 23 | * 24 | * @author Refresh yoonus 25 | */ 26 | object Demo { 27 | 28 | /** 29 | * Adds the demo product to inventory. 30 | * @param context The current stage of the application. 31 | */ 32 | fun testProduct(context: Context) { 33 | val instream = context.resources.openRawResource(R.raw.products) 34 | val reader = BufferedReader(InputStreamReader(instream)) 35 | var line: String 36 | try { 37 | val catalog = Inventory.getInstance().getProductCatalog() 38 | 39 | var count = 1 40 | var catId=1000; 41 | while (count<15) { 42 | line = reader.readLine() 43 | val contents = line.split(",".toRegex()).dropLastWhile({ it.isEmpty() }).toTypedArray() 44 | Log.d("Demo", contents[0] + ":" + contents[1] + ": " + contents[2]) 45 | catId++ 46 | catalog.addProduct(contents[1],contents[0].toInt(), contents[0], (contents[2]).toString().toBigDecimal(),"kg", BigDecimal.TEN,catId,"",1,10.toDouble(),true,4.toBigDecimal()) 47 | if(count%3==0) 48 | { 49 | catId++ 50 | } 51 | count++ 52 | if(count==15) 53 | { 54 | break 55 | } 56 | 57 | } 58 | }catch (e: Exception) { 59 | e.printStackTrace() 60 | } 61 | 62 | } 63 | 64 | 65 | fun testaddTax(context: Context) { 66 | 67 | try { 68 | val Taxs = TaxDbo.getInstance(context) 69 | var count = 1; 70 | var TaxId=0 71 | 72 | while (count <4) { 73 | TaxId++ 74 | var demmuyTax= Tax(TaxId,"demoTax"+1+TaxId+"%",(10+TaxId).toDouble(),false) 75 | var instatus:Int= Taxs.addTax(demmuyTax) 76 | Log.e("instatus",instatus.toString()) 77 | 78 | TaxId= count++ 79 | 80 | } 81 | }catch (e: Exception) { 82 | e.printStackTrace() 83 | } 84 | 85 | } 86 | 87 | 88 | 89 | fun testCategory(context: Context) { 90 | try { 91 | val category = CategoryDbo.getInstance(context) 92 | var count = 1; 93 | var catId=1000 94 | while (count <10) { 95 | 96 | var demmuyCategry=Category(0,"demoCate"+catId,catId,"") 97 | category.addCategory(demmuyCategry) 98 | catId= 99 | count++ 100 | if(count==15) 101 | { 102 | break 103 | } 104 | } 105 | }catch (e: Exception) { 106 | e.printStackTrace() 107 | } 108 | 109 | } 110 | 111 | 112 | fun testCustomer(context: Context) { 113 | val instream = context.resources.openRawResource(R.raw.products) 114 | val reader = BufferedReader(InputStreamReader(instream)) 115 | var line: String 116 | try { 117 | val customerDB = CustomerDbao.getInstance(context) 118 | line = reader.readLine() 119 | var count = 0 120 | while (count<14) { 121 | var customer= CustomerModel() 122 | customer.customerId=count+1000 123 | customer.customerName="DemoCustomer"+count 124 | customer.customerCode="cs"+count 125 | customer.countryName="India" 126 | customer.city="calicut" 127 | customer.address1="abcd" 128 | customer.address2="abcd" 129 | customer.email="abcd@gmail.com" 130 | customer.postalCode="123456789" 131 | customer.seaquenceNo="000"+count 132 | customer.isActive=true 133 | customer.isNew=false 134 | customer.status= "S" 135 | customer.poPriceListId=1 136 | customer.poPriceListId=1 137 | customer.phone="812993485" 138 | customer.taxId="15" 139 | customer.isNoTax=false 140 | customer.regionName="kerala" 141 | customer.stateCode="kl" 142 | customer.isCustomer=true 143 | customer.isVendor=false 144 | customer.isEmployee=false 145 | customer.isSalesRep=false 146 | customer.countryId=1258 147 | customer.regionID=12 148 | customer.profileId=0 149 | 150 | count++ 151 | if(count==15) 152 | { 153 | break 154 | } 155 | customerDB.addCustomer(customer) 156 | 157 | } 158 | }catch (e: Exception) { 159 | e.printStackTrace() 160 | } 161 | 162 | } 163 | 164 | 165 | } 166 | -------------------------------------------------------------------------------- /db/NoDaoSetException.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.db 2 | 3 | /** 4 | * Exception of when trying to getInstance() without inject its DAO. 5 | * 6 | * @author Ionob Team 7 | */ 8 | class NoDaoSetException : Exception() { 9 | companion object { 10 | 11 | private val serialVersionUID = 1L 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /db/Tax/Tax.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.db.Tax 2 | 3 | open class Tax ( 4 | 5 | val tax_id: Int, 6 | var tax_name:String?, 7 | var tax_percent:Double?, 8 | var tax_mode: Boolean 9 | ) 10 | -------------------------------------------------------------------------------- /db/Tax/TaxDao.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.db.Tax 2 | 3 | interface TaxDao { 4 | 5 | val allTax: List 6 | 7 | fun getTax_byid(TaxId: Int):List 8 | 9 | fun addTax(tax:Tax):Int 10 | 11 | fun EditTax(tax: Tax) 12 | 13 | fun UpdateTax(tax: Tax) 14 | 15 | fun deleteTax(TaxId:Int) 16 | 17 | } -------------------------------------------------------------------------------- /db/Tax/TaxDbo.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.db.Tax 2 | 3 | import android.content.ContentValues 4 | import android.content.Context 5 | import android.util.Log 6 | import com.ionob.pos.db.AndroidDatabase 7 | import com.ionob.pos.db.Database 8 | import com.ionob.pos.db.DatabaseContents 9 | import com.ionob.pos.db.NoDaoSetException 10 | import com.ionob.pos.domain.inventory.Category 11 | import java.util.ArrayList 12 | 13 | class TaxDbo(private val database: Database) : TaxDao { 14 | 15 | 16 | 17 | override val allTax: List 18 | get() = getTaxlist() 19 | 20 | 21 | override fun addTax(tax: Tax): Int { 22 | val content = ContentValues() 23 | content.put("tax_id", tax.tax_id) 24 | content.put("tax_name", tax.tax_name) 25 | content.put("tax_percent", tax.tax_percent?.toDouble()) 26 | content.put("is_tax_inclusive", tax.tax_mode) 27 | val id = database.insert(DatabaseContents.TABLE_TAX.toString(), content) 28 | return id 29 | 30 | } 31 | 32 | override fun EditTax(tax: Tax) { 33 | 34 | 35 | TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 36 | } 37 | 38 | override fun UpdateTax(tax: Tax) { 39 | 40 | 41 | TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 42 | } 43 | 44 | override fun deleteTax(TaxId: Int) { 45 | TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 46 | } 47 | 48 | fun getTaxlist(): List { 49 | val queryString = "SELECT * FROM " + DatabaseContents.TABLE_TAX.toString() 50 | Log.d("query", queryString) 51 | return totax(database.select(queryString)!!) 52 | } 53 | 54 | 55 | override fun getTax_byid(tax_id: Int):List { 56 | 57 | val queryString = "SELECT * FROM " + DatabaseContents.TABLE_TAX.toString()+" WHERE tax_id= "+tax_id.toString()+"" 58 | Log.d("query", queryString) 59 | return totax(database.select(queryString)!!) 60 | 61 | } 62 | 63 | 64 | private fun totax(objectList: List): List { 65 | val list = ArrayList() 66 | for (`object` in objectList) { 67 | val content = `object` as ContentValues 68 | 69 | list.add(Tax( 70 | content.getAsInteger("tax_id")!!, 71 | content.getAsString("tax_name"), 72 | content.getAsDouble("tax_percent"), 73 | content.getAsBoolean("is_tax_inclusive") 74 | ) 75 | ) 76 | } 77 | return list 78 | } 79 | 80 | 81 | 82 | 83 | 84 | companion object { 85 | 86 | private var instance: TaxDbo? = null 87 | @Throws(NoDaoSetException::class) 88 | fun getInstance(context: Context): TaxDbo { 89 | if (TaxDbo.instance == null) TaxDbo.instance = TaxDbo(AndroidDatabase(context)) 90 | return TaxDbo.instance as TaxDbo 91 | } 92 | } 93 | 94 | 95 | } 96 | 97 | 98 | -------------------------------------------------------------------------------- /db/Tax/tax_model.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.db.Tax 2 | 3 | open class tax_model { 4 | 5 | var id: Int = 0 6 | var taxid: Int = 0 7 | var tax_name: String?=null 8 | var taxt_percent: Double?=null 9 | var tax_type: String?=null 10 | 11 | 12 | 13 | 14 | } -------------------------------------------------------------------------------- /db/customer/CustomerDao.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.db.customer 2 | 3 | import com.ionob.pos.domain.inventory.Product 4 | import com.ionob.pos.domain.inventory.ProductLot 5 | import com.ionob.pos.ui.sale.model.CustomerModel 6 | 7 | /** 8 | * DAO for Inventory. 9 | * 10 | * @author Ionob Team 11 | */ 12 | interface CustomerDao { 13 | 14 | /** 15 | * Returns list of all products in inventory. 16 | * @return list of all products in inventory. 17 | */ 18 | val allCustomer: List 19 | 20 | 21 | 22 | /** 23 | * Adds new customer in to db 24 | * @param customer the customer to be added. 25 | * @return id of record that assigned from database. 26 | */ 27 | fun addCustomer(customer: CustomerModel): Int 28 | 29 | 30 | 31 | /** 32 | * Edits customer 33 | * @param customer the customer to be edited. 34 | * @return true if success ; otherwise false. 35 | */ 36 | fun editCustomer(customer: CustomerModel?): Boolean 37 | 38 | /** 39 | * Returns customer from db . 40 | * @param id id of customer . 41 | * @return customer 42 | */ 43 | fun getCustomerByid(customerId: Int): CustomerModel 44 | 45 | 46 | /** 47 | * Returns list of customer 48 | * @param name name of customer . 49 | * @return list of customer finds by name. 50 | */ 51 | fun getCustomerByName(name: String): List 52 | 53 | /** 54 | * Search product from string in inventory. 55 | * @param search string for searching. 56 | * @return list of product. 57 | */ 58 | fun searchCustomer(search: String): List 59 | 60 | /** 61 | * Returns list of product in inventory finds by id. 62 | * @param id id of product. 63 | * @return list of product in inventory finds by id. 64 | */ 65 | 66 | 67 | 68 | 69 | fun deleteall() 70 | 71 | 72 | 73 | } 74 | -------------------------------------------------------------------------------- /db/customer/CustomerDbao.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.db.customer 2 | 3 | import java.util.ArrayList 4 | 5 | import android.content.ContentValues 6 | import android.content.Context 7 | import android.util.Log 8 | import com.ionob.pos.db.AndroidDatabase 9 | 10 | import com.ionob.pos.domain.inventory.Product 11 | import com.ionob.pos.domain.inventory.ProductLot 12 | import com.ionob.pos.db.Database 13 | import com.ionob.pos.db.DatabaseContents 14 | import com.ionob.pos.db.NoDaoSetException 15 | import com.ionob.pos.domain.sale.Register 16 | import com.ionob.pos.ui.sale.model.CustomerModel 17 | import java.math.BigDecimal 18 | 19 | /** 20 | * DAO used by android for Inventory. 21 | * 22 | * @author yoonus 23 | */ 24 | class CustomerDbao 25 | /** 26 | * Constructs InventoryDaoAndroid. 27 | * @param database database for use in InventoryDaoAndroid. 28 | */ 29 | (private val database: Database) : CustomerDao { 30 | 31 | override val allCustomer: List 32 | get() = getAllCustomer(" WHERE 1 = 1 ") 33 | 34 | 35 | override fun addCustomer(customer: CustomerModel): Int { 36 | val content = ContentValues() 37 | //content.put("id") 38 | content.put("customer_id",customer.customerId) 39 | content.put("customer_name",customer.customerName) 40 | content.put("customer_code",customer.customerCode) 41 | content.put("country",customer.countryName) 42 | content.put("city",customer.city) 43 | content.put("address1",customer.address1) 44 | content.put("address2",customer.address2) 45 | content.put("email",customer.email) 46 | content.put("postal_code",customer.postalCode) 47 | content.put("seaquenceNo",customer.seaquenceNo) 48 | content.put("isActive",customer.isActive) 49 | content.put("isNew",customer.isNew) 50 | content.put("status",customer.status) 51 | content.put("poPriceListId",customer.poPriceListId) 52 | content.put("soPriceListId",customer.soPriceListId) 53 | content.put("phone",customer.phone) 54 | content.put("taxId",customer.taxId) 55 | content.put("isNoTax",customer.isNoTax) 56 | content.put("regionName",customer.regionName) 57 | content.put("stateCode",customer.stateCode) 58 | content.put("isCustomer",customer.isCustomer) 59 | content.put("isVendor",customer.isVendor) 60 | content.put("isEmployee",customer.isEmployee) 61 | content.put("isSalesRep",customer.isSalesRep) 62 | content.put("countryId",customer.countryId) 63 | content.put("regionID",customer.regionID) 64 | content.put("profile_id",customer.profileId) 65 | return database.insert(DatabaseContents.TABLE_CUSTOMER.toString(), content) 66 | } 67 | 68 | 69 | /** 70 | * Converts list of object to list of product. 71 | * @param objectList list of object. 72 | * @return list of product. 73 | */ 74 | /* "CREATE TABLE IF NOT EXISTS " + DatabaseContents.TABLE_CUSTOMER + "(" + "id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL ," + 75 | " customer_id INTEGER , customer_name TEXT , customer_code TEXT , " + 76 | " country TEXT , city TEXT , address1 TEXT , address2 TEXT ," + 77 | " email TEXT, postal_code TEXT, seaquenceNo TEXT,isActive BOOLEAN,isNew BOOLEAN," + 78 | " status TEXT , poPriceListId INTEGER , soPriceListId INTEGER , phone TEXT , " + 79 | " taxId INTEGER , isNoTax BOOLEAN , regionName TEXT , stateCode TEXT , " + 80 | " isCustomer BOOLEAN , isVendor BOOLEAN , isEmployee BOOLEAN , isSalesRep BOOLEAN , " + 81 | " countryId INTEGER ,regionID INTEGER, inprofile_id INTEGER" + ");")*/ 82 | 83 | private fun toCustomer(objectList: List): List { 84 | val list = ArrayList() 85 | for (`object` in objectList) { 86 | val content = `object` as ContentValues 87 | var customer=CustomerModel() 88 | customer.id =content.getAsInteger("_id") 89 | customer.customerId=content.getAsInteger("customer_id") 90 | customer.customerName=content.getAsString("customer_name") 91 | customer.customerCode=content.getAsString("customer_code") 92 | customer.countryName=content.getAsString("country") 93 | customer.city=content.getAsString("city") 94 | customer.address1=content.getAsString("address1") 95 | customer.address2=content.getAsString("address2") 96 | customer.email=content.getAsString("email") 97 | customer.postalCode=content.getAsString("postal_code") 98 | customer.seaquenceNo=content.getAsString("seaquenceNo") 99 | customer.isActive=content.getAsBoolean("isActive") 100 | customer.isNew=content.getAsBoolean("isNew") 101 | customer.status=content.getAsString("status") 102 | customer.poPriceListId=content.getAsInteger("poPriceListId") 103 | customer.poPriceListId=content.getAsInteger("soPriceListId") 104 | customer.phone=content.getAsString("phone") 105 | customer.taxId=content.getAsString("taxId") 106 | customer.isNoTax=content.getAsBoolean("isNoTax") 107 | customer.regionName=content.getAsString("regionName") 108 | customer.stateCode=content.getAsString("stateCode") 109 | customer.isCustomer=content.getAsBoolean("isCustomer") 110 | customer.isVendor=content.getAsBoolean("isVendor") 111 | customer.isEmployee=content.getAsBoolean("isEmployee") 112 | customer.isSalesRep=content.getAsBoolean("isSalesRep") 113 | customer.countryId=content.getAsInteger("countryId") 114 | customer.regionID=content.getAsInteger("regionID") 115 | customer.profileId=content.getAsInteger("inprofile_id")?:0 116 | list.add(customer) 117 | 118 | } 119 | return list 120 | } 121 | 122 | /** 123 | * Returns list of all products in inventory. 124 | * @param condition specific condition for getAllProduct. 125 | * @return list of all products in inventory. 126 | */ 127 | private fun getAllCustomer(condition: String): List { 128 | val queryString = "SELECT * FROM " + DatabaseContents.TABLE_CUSTOMER.toString() + condition + " ORDER BY customer_name" 129 | Log.d("query",queryString) 130 | return toCustomer(database.select(queryString)!!) 131 | } 132 | 133 | 134 | override fun getCustomerByid(customerId: Int): CustomerModel { 135 | return getAllCustomer(" WHERE customer_id= "+customerId.toString()+"")[0] 136 | } 137 | 138 | override fun getCustomerByName(name: String): List { 139 | return getAllCustomer(" WHERE customer_name= "+name+"") 140 | } 141 | 142 | override fun searchCustomer(search: String): List { 143 | val condition = " WHERE name LIKE '%$search%' OR barcode LIKE '%$search%' ;" 144 | return getAllCustomer(condition) 145 | } 146 | 147 | override fun editCustomer(customer: CustomerModel?): Boolean { 148 | val content = ContentValues() 149 | customer?.let { 150 | content.put("id", customer.id) 151 | content.put("customer_id", customer.customerId) 152 | content.put("customer_name", customer.customerName) 153 | content.put("customer_code", customer.customerCode) 154 | content.put("country", customer.countryName) 155 | content.put("city", customer.city) 156 | content.put("address1", customer.address1) 157 | content.put("address2", customer.address2) 158 | content.put("email", customer.email) 159 | content.put("postal_code", customer.postalCode) 160 | content.put("seaquenceNo", customer.seaquenceNo) 161 | content.put("isActive", customer.isActive) 162 | content.put("isNew", customer.isNew) 163 | content.put("status", customer.status) 164 | content.put("poPriceListId", customer.poPriceListId) 165 | content.put("soPriceListId", customer.soPriceListId) 166 | content.put("phone", customer.phone) 167 | content.put("taxId", customer.taxId) 168 | content.put("isNoTax", customer.isNoTax) 169 | content.put("regionName", customer.regionName) 170 | content.put("stateCode", customer.stateCode) 171 | content.put("isCustomer", customer.isCustomer) 172 | content.put("isVendor", customer.isVendor) 173 | content.put("isEmployee", customer.isEmployee) 174 | content.put("isSalesRep", customer.isSalesRep) 175 | content.put("countryId", customer.countryId) 176 | content.put("regionID", customer.regionID) 177 | content.put("profile_id", customer.profileId) 178 | return database.update(DatabaseContents.TABLE_CUSTOMER.toString(), content) 179 | } 180 | return false 181 | } 182 | 183 | 184 | override fun deleteall() { 185 | database.execute("DELETE FROM " + DatabaseContents.TABLE_CUSTOMER) 186 | } 187 | companion object { 188 | private var instance: CustomerDbao? = null 189 | 190 | 191 | @Throws(NoDaoSetException::class) 192 | fun getInstance(context: Context): CustomerDbao { 193 | if (CustomerDbao.instance == null) CustomerDbao.instance = CustomerDbao(AndroidDatabase(context)) 194 | return CustomerDbao.instance as CustomerDbao 195 | } 196 | } 197 | 198 | } 199 | -------------------------------------------------------------------------------- /db/inventory/CategoryDao.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.db.inventory 2 | 3 | import com.ionob.pos.domain.inventory.Category 4 | import com.ionob.pos.domain.inventory.Product 5 | import com.ionob.pos.domain.inventory.ProductLot 6 | 7 | /** 8 | * DAO for Inventory. 9 | * 10 | * @author yoonus 11 | */ 12 | interface CategoryDao { 13 | 14 | /** 15 | * Returns list of all products in inventory. 16 | * @return list of all products in inventory. 17 | */ 18 | val allCategory: List 19 | fun addCategory(category: Category): Int 20 | fun editCatogory(product: Category?): Boolean 21 | fun getCategoryById(id: Int): Category 22 | fun getCategoryByName(name: String): List 23 | fun searchCategory(search: String): List 24 | fun clearCategory() 25 | } 26 | -------------------------------------------------------------------------------- /db/inventory/CategoryDbo.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.db.inventory 2 | 3 | import java.util.ArrayList 4 | 5 | import android.content.ContentValues 6 | import android.content.Context 7 | import android.util.Log 8 | import com.ionob.pos.db.AndroidDatabase 9 | 10 | import com.ionob.pos.domain.inventory.Product 11 | import com.ionob.pos.domain.inventory.ProductLot 12 | import com.ionob.pos.db.Database 13 | import com.ionob.pos.db.DatabaseContents 14 | import com.ionob.pos.db.NoDaoSetException 15 | import com.ionob.pos.db.customer.CustomerDbao 16 | import com.ionob.pos.domain.inventory.Category 17 | import java.math.BigDecimal 18 | 19 | /** 20 | * DAO used by android for category. 21 | * 22 | * @author yoonus 23 | */ 24 | class CategoryDbo 25 | /** 26 | * Constructs InventoryDaoAndroid. 27 | * @param database database for use in InventoryDaoAndroid. 28 | */ 29 | (private val database: Database) : CategoryDao { 30 | 31 | override val allCategory: List 32 | get() = getAllCategory(" WHERE 1=1") 33 | 34 | 35 | override fun addCategory(category: Category): Int { 36 | val content = ContentValues() 37 | content.put("category_name", category.name) 38 | content.put("category_id", category.categoryID) 39 | content.put("image", category.image) 40 | val id = database.insert(DatabaseContents.TABLE_PRODUCT_CATEGORY.toString(), content) 41 | return id 42 | } 43 | 44 | /** 45 | * Converts list of object to list of product. 46 | * @param objectList list of object. 47 | * @return list of product. 48 | */ 49 | private fun toCategory(objectList: List): List { 50 | val list = ArrayList() 51 | for (`object` in objectList) { 52 | val content = `object` as ContentValues 53 | list.add(Category( 54 | content.getAsInteger("_id")!!, 55 | content.getAsString("category_name"), 56 | content.getAsInteger("category_id"), 57 | content.getAsString("image").toString() 58 | ) 59 | ) 60 | } 61 | return list 62 | } 63 | 64 | /** 65 | * Returns list of all products in inventory. 66 | * @param condition specific condition for getAllProduct. 67 | * @return list of all products in inventory. 68 | */ 69 | private fun getAllCategory(condition: String): List { 70 | val queryString = "SELECT * FROM " + DatabaseContents.TABLE_PRODUCT_CATEGORY.toString()+condition + " ORDER BY category_name" 71 | Log.d("query",queryString) 72 | return toCategory(database.select(queryString)!!) 73 | } 74 | 75 | /** 76 | * Returns product from inventory finds by specific reference. 77 | * @param reference reference value. 78 | * @param value value for search. 79 | * @return list of product. 80 | */ 81 | private fun getProductBy(reference: String, value: String): List { 82 | val condition = " WHERE $reference = $value ;" 83 | return getAllCategory(condition) 84 | } 85 | 86 | /** 87 | * Returns product from inventory finds by similar name. 88 | * @param reference reference value. 89 | * @param value value for search. 90 | * @return list of product. 91 | */ 92 | private fun getSimilarProductBy(reference: String, value: String): List { 93 | val condition = " WHERE $reference LIKE '%$value%' ;" 94 | return getAllCategory(condition) 95 | } 96 | 97 | 98 | override fun getCategoryById(catid: Int): Category { 99 | return getProductBy("category_id", catid.toString() + "")[0] 100 | } 101 | 102 | // override fun getCategoryByLineid(id: Int): Category { 103 | // return getProductBy("_id", id.toString() + "")[0] 104 | // } 105 | 106 | 107 | override fun editCatogory(category: Category?): Boolean { 108 | val content = ContentValues() 109 | content.put("_id", category?.id) 110 | content.put("category_name", category?.name) 111 | content.put("category_id", category?.categoryID) 112 | content.put("image", category?.image) 113 | return database.update(DatabaseContents.TABLE_PRODUCT_CATEGORY.toString(), content) 114 | } 115 | 116 | 117 | override fun getCategoryByName(name: String): List { 118 | return getSimilarProductBy("category_name", name) 119 | } 120 | 121 | override fun searchCategory(search: String): List { 122 | val condition = " WHERE category_name LIKE '%$search%' ;" 123 | return getAllCategory(condition) 124 | } 125 | 126 | 127 | override fun clearCategory() { 128 | database.execute("DELETE FROM " + DatabaseContents.TABLE_PRODUCT_CATEGORY) 129 | } 130 | 131 | 132 | companion object { 133 | private var instance: CategoryDbo? = null 134 | 135 | 136 | @Throws(NoDaoSetException::class) 137 | fun getInstance(context: Context): CategoryDbo { 138 | if (CategoryDbo.instance == null) CategoryDbo.instance = CategoryDbo(AndroidDatabase(context)) 139 | return CategoryDbo.instance as CategoryDbo 140 | } 141 | } 142 | 143 | 144 | 145 | } 146 | -------------------------------------------------------------------------------- /db/inventory/InventoryDao.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.db.inventory 2 | 3 | import com.ionob.pos.domain.inventory.Product 4 | import com.ionob.pos.domain.inventory.ProductLot 5 | 6 | /** 7 | * DAO for Inventory. 8 | * 9 | * @author Ionob Team 10 | */ 11 | interface InventoryDao { 12 | 13 | /** 14 | * Returns list of all products in inventory. 15 | * @return list of all products in inventory. 16 | */ 17 | val allProduct: List 18 | 19 | /** 20 | * Returns list of all products in inventory. 21 | * @return list of all products in inventory. 22 | */ 23 | val allProductLot: List 24 | 25 | /** 26 | * Adds product to inventory. 27 | * @param product the product to be added. 28 | * @return id of this product that assigned from database. 29 | */ 30 | fun addProduct(product: Product): Int 31 | 32 | /** 33 | * Adds ProductLot to inventory. 34 | * @param productLot the ProductLot to be added. 35 | * @return id of this ProductLot that assigned from database. 36 | */ 37 | fun addProductLot(productLot: ProductLot): Int 38 | 39 | /** 40 | * Edits product. 41 | * @param product the product to be edited. 42 | * @return true if product edits success ; otherwise false. 43 | */ 44 | fun editProduct(product: Product?): Boolean 45 | 46 | /** 47 | * Returns product from inventory finds by id. 48 | * @param id id of product. 49 | * @return product 50 | */ 51 | fun getProductById(id: Int): Product 52 | 53 | /** 54 | * Returns product from inventory finds by barcode. 55 | * @param barcode barcode of product. 56 | * @return product 57 | */ 58 | fun getProductByBarcode(barcode: String): Product? 59 | 60 | /** 61 | * Returns list of product in inventory finds by name. 62 | * @param name name of product. 63 | * @return list of product in inventory finds by name. 64 | */ 65 | fun getProductByName(name: String): List 66 | 67 | /** 68 | * Search product from string in inventory. 69 | * @param search string for searching. 70 | * @return list of product. 71 | */ 72 | fun searchProduct(search: String): List 73 | 74 | /** 75 | * Returns list of product in inventory finds by id. 76 | * @param id id of product. 77 | * @return list of product in inventory finds by id. 78 | */ 79 | fun getProductLotById(id: Int): List 80 | 81 | /** 82 | * Returns list of ProductLot in inventory finds by id. 83 | * @param id id of ProductLot. 84 | * @return list of ProductLot in inventory finds by id. 85 | */ 86 | fun getProductLotByProductId(id: Int): List 87 | 88 | /** 89 | * Returns Stock in inventory finds by id. 90 | * @param id id of Stock. 91 | * @return Stock in inventory finds by id. 92 | */ 93 | fun getStockSumById(id: Int?): Int 94 | 95 | /** 96 | * Updates quantity of product. 97 | * @param productId id of product. 98 | * @param quantity quantity of product. 99 | */ 100 | fun updateStockSum(productId: Int?, quantity: Double) 101 | 102 | /** 103 | * Clears ProductCatalog. 104 | */ 105 | fun clearProductCatalog() 106 | 107 | /** 108 | * Clear Stock. 109 | */ 110 | fun clearStock() 111 | 112 | /** 113 | * Hidden product from inventory. 114 | * @param product The product to be hidden. 115 | */ 116 | fun suspendProduct(product: Product?) 117 | 118 | } 119 | -------------------------------------------------------------------------------- /db/sale/SaleDao.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.db.sale 2 | 3 | import java.util.Calendar 4 | 5 | import com.ionob.pos.domain.inventory.LineItem 6 | import com.ionob.pos.domain.sale.Sale 7 | 8 | /** 9 | * DAO for Sale process. 10 | * 11 | * @author Ionob Team 12 | */ 13 | interface SaleDao { 14 | 15 | /** 16 | * Returns all sale in the records. 17 | * @return all sale in the records. 18 | */ 19 | 20 | val allSale: List 21 | val allCompletedSale: List 22 | val allDraftSale: List 23 | val allSynced: List 24 | val allFailed: List 25 | fun getCoutOfRecord(status:String): Int 26 | 27 | /** 28 | * Initiates a new Sale. 29 | * @param startTime time that Sale initiated. 30 | * @return Sale that initiated 31 | */ 32 | fun initiateSale(startTime: String): Sale? 33 | 34 | 35 | fun initiateSale(sales: Sale): Sale 36 | 37 | /** 38 | * End Sale 39 | * @param sale Sale to be ended. 40 | * @param endTime time that Sale ended. 41 | */ 42 | fun endSale(sale: Sale, endTime: String) 43 | 44 | /** 45 | * Add LineItem to Sale. 46 | * @param saleId ID of the Sale to add LineItem. 47 | * @param lineItem LineItem to be added. 48 | * @return ID of LineItem that just added. 49 | */ 50 | 51 | fun updateSale(sale: Sale) 52 | 53 | 54 | fun addLineItem(saleId: Int, lineItem: LineItem): Int 55 | 56 | /** 57 | * Returns the Sale with specific ID. 58 | * @param id ID of specific Sale. 59 | * @return the Sale with specific ID. 60 | */ 61 | fun getSaleById(id: Int): Sale 62 | 63 | /** 64 | * Clear all records in SaleLedger. 65 | */ 66 | fun clearSaleLedger() 67 | 68 | 69 | fun deleteSalesRecord(salesId:Int) 70 | 71 | /** 72 | * Returns list of LineItem that belong to Sale with specific Sale ID. 73 | * @param saleId ID of sale. 74 | * @return list of LineItem that belong to Sale with specific Sale ID. 75 | */ 76 | fun getLineItem(saleId: Int): List 77 | 78 | 79 | fun getLine(saleId: Int,lineid:Int): LineItem? 80 | 81 | /** 82 | * Updates the data of specific LineItem. 83 | * @param saleId ID of Sale that this LineItem belong to. 84 | * @param lineItem to be updated. 85 | */ 86 | fun updateLineItem(saleId: Int, lineItem: LineItem) 87 | 88 | /** 89 | * Returns list of Sale with scope of time. 90 | * @param start start bound of scope. 91 | * @param end end bound of scope. 92 | * @return list of Sale with scope of time. 93 | */ 94 | fun getAllSaleDuring(start: Calendar, end: Calendar): List 95 | 96 | /** 97 | * Cancel the Sale. 98 | * @param sale Sale to be cancel. 99 | * @param endTime time that cancelled. 100 | */ 101 | fun cancelSale(sale: Sale, endTime: String) 102 | 103 | /** 104 | * Removes LineItem. 105 | * @param id of LineItem to be removed. 106 | */ 107 | fun removeLineItem(id: Int) 108 | 109 | companion object { 110 | val STATUS_SYNCED="SYNCED" 111 | val STATUS_SYNC_FAILED="FAILED" 112 | val STATUS_COMPLETED="COMLETED" 113 | val STATUS_DRAFT="DRAFT" 114 | val STATUS_ALL="all" 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /domain/DateTimeStrategy.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.domain 2 | 3 | import java.text.SimpleDateFormat 4 | import java.util.Calendar 5 | import java.util.Locale 6 | 7 | /** 8 | * A static class, global access for how to handle with date format. 9 | * 10 | * @author Ionob Team 11 | */ 12 | object DateTimeStrategy { 13 | 14 | private var locale: Locale? = null 15 | private var dateFormat: SimpleDateFormat? = null 16 | 17 | /** 18 | * Returns current time. 19 | * @return current time. 20 | */ 21 | val currentTime: String 22 | get() = dateFormat!!.format(Calendar.getInstance().time).toString() 23 | 24 | /** 25 | * Set local of time for use in application. 26 | * @param lang Language. 27 | * @param reg Region. 28 | */ 29 | fun setLocale(lang: String, reg: String) { 30 | locale = Locale(lang, reg) 31 | dateFormat = SimpleDateFormat("yyyy-MM-dd hh:mm:ss", locale!!) 32 | } 33 | 34 | /** 35 | * Sets current time format. 36 | * @param date date of this format. 37 | * @return current time format. 38 | */ 39 | fun format(date: String): String { 40 | return dateFormat!!.format(date) 41 | } 42 | 43 | /** 44 | * Convert the calendar format to date format for adapt in SQL. 45 | * @param instance calendar . 46 | * @return date format. 47 | */ 48 | fun getSQLDateFormat(instance: Calendar): String { 49 | return dateFormat!!.format(instance.time).toString().substring(0, 10) 50 | } 51 | 52 | }// Static class 53 | -------------------------------------------------------------------------------- /domain/LanguageController.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.domain 2 | 3 | import android.content.ContentValues 4 | 5 | import com.ionob.pos.db.Database 6 | import com.ionob.pos.db.DatabaseContents 7 | 8 | /** 9 | * Saves and loads language preference from database. 10 | * 11 | * @author Ionob Team 12 | */ 13 | class LanguageController private constructor() { 14 | 15 | /** 16 | * Returns current language. 17 | * @return current language. 18 | */ 19 | /** 20 | * Sets language for use in application. 21 | * @param localeString local string of country. 22 | */ 23 | var language: String 24 | get() { 25 | val contents = database!!.select("SELECT * FROM " + DatabaseContents.LANGUAGE) 26 | 27 | if (contents!!.isEmpty()) { 28 | val defualtLang = ContentValues() 29 | defualtLang.put("language", DEFAULT_LANGUAGE) 30 | database!!.insert(DatabaseContents.LANGUAGE.toString(), defualtLang) 31 | 32 | return DEFAULT_LANGUAGE 33 | } 34 | val content = contents[0] as ContentValues 35 | return content.getAsString("language") 36 | } 37 | set(localeString) { 38 | database!!.execute("UPDATE " + DatabaseContents.LANGUAGE + " SET language = '" + localeString + "'") 39 | } 40 | 41 | companion object { 42 | 43 | private val DEFAULT_LANGUAGE = "en" 44 | private var database: Database? = null 45 | private var instance: LanguageController? = null 46 | 47 | internal fun getInstance(): LanguageController { 48 | if (instance == null) 49 | instance = LanguageController() 50 | return instance as LanguageController 51 | } 52 | 53 | /** 54 | * Sets database for use in this class. 55 | * @param db database. 56 | */ 57 | internal fun setDatabase(db: Database) { 58 | database = db 59 | } 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /domain/inventory/Category.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.domain.inventory 2 | 3 | import java.math.BigDecimal 4 | import java.util.HashMap 5 | 6 | /** 7 | * Product or item represents the real product in store. 8 | * 9 | * @author yoonus 10 | */ 11 | open class Category( 12 | val id: Int, 13 | var name: String?, 14 | var categoryID:Int?, 15 | var image: String? 16 | ) 17 | 18 | 19 | -------------------------------------------------------------------------------- /domain/inventory/Inventory.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.domain.inventory 2 | 3 | import com.ionob.pos.db.NoDaoSetException 4 | import com.ionob.pos.db.inventory.InventoryDao 5 | 6 | 7 | /** 8 | * This class is service locater for Product Catalog and Stock. 9 | * 10 | * @author Ionob Team 11 | */ 12 | class Inventory 13 | /** 14 | * Constructs Data Access Object of inventory. 15 | * @throws NoDaoSetException if DAO is not exist. 16 | */ 17 | @Throws(NoDaoSetException::class) constructor() { 18 | 19 | /** 20 | * Returns stock using in this inventory. 21 | * @return stock using in this inventory. 22 | */ 23 | val stock: Stock 24 | /** 25 | * Returns product catalog using in this inventory. 26 | * @return product catalog using in this inventory. 27 | */ 28 | private val productCatalog: ProductCatalog 29 | 30 | init { 31 | if (!isDaoSet()) { 32 | throw NoDaoSetException() 33 | } 34 | stock = Stock(inventoryDao) 35 | productCatalog = ProductCatalog(inventoryDao) 36 | } 37 | 38 | internal fun getStock(): Stock { 39 | return stock 40 | } 41 | 42 | public fun getProductCatalog(): ProductCatalog { 43 | return productCatalog 44 | } 45 | 46 | 47 | companion object { 48 | private var instance: Inventory? = null 49 | private var inventoryDao: InventoryDao? = null 50 | 51 | 52 | /** 53 | * Determines whether the DAO already set or not. 54 | * @return true if the DAO already set; otherwise false. 55 | */ 56 | 57 | fun isDaoSet():Boolean { 58 | if(inventoryDao != null) 59 | { 60 | return true 61 | } 62 | return false 63 | } 64 | 65 | /** 66 | * Sets the database connector. 67 | * @param dao Data Access Object of inventory. 68 | */ 69 | internal fun setInventoryDao(dao: InventoryDao) { 70 | this.inventoryDao = dao 71 | } 72 | 73 | /** 74 | * Returns the instance of this singleton class. 75 | * @return instance of this class. 76 | * @throws NoDaoSetException if DAO was not set. 77 | */ 78 | @Throws(NoDaoSetException::class) 79 | internal fun getInstance(): Inventory { 80 | if (instance == null) 81 | instance = Inventory() 82 | return instance as Inventory 83 | } 84 | } 85 | 86 | 87 | } 88 | 89 | -------------------------------------------------------------------------------- /domain/inventory/LineItem.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.domain.inventory 2 | 3 | import java.math.BigDecimal 4 | import java.text.DecimalFormat 5 | 6 | /** 7 | * LineItem of Sale. 8 | * 9 | * @author YOONUS 10 | */ 11 | class LineItem 12 | /** 13 | * Constructs a new LineItem. 14 | * @param id ID of this LineItem, This value should be assigned from database. 15 | * @param product product of this LineItem. 16 | * @param quantity product quantity of this LineItem. 17 | * @param unitPriceAtSale unit price at sale time. default is price from ProductCatalog. 18 | * @param discount line discount. 19 | * @param taxAmount line tax amount. 20 | */ 21 | (var id: Int, val product: Product?, var quantity: BigDecimal, private var unitPriceAtSale: BigDecimal? 22 | , var discount:BigDecimal= BigDecimal.ZERO , var taxAmount:BigDecimal= BigDecimal.ZERO) { 23 | 24 | 25 | var trim= DecimalFormat("00.00") 26 | 27 | var totalAmount: BigDecimal?= BigDecimal.ZERO 28 | get() = unitPriceAtSale?.multiply(quantity) 29 | 30 | var netAmount: BigDecimal?= BigDecimal.ZERO 31 | get() = this.totalAmount?.subtract(this.discount) 32 | 33 | val priceAtSale: BigDecimal? 34 | get() = unitPriceAtSale 35 | 36 | var totalTax: BigDecimal? = BigDecimal.ZERO 37 | get() =taxamount() 38 | 39 | var totalpercent: BigDecimal? = BigDecimal.ZERO 40 | get() =product!!.tax_percent.toBigDecimal() 41 | 42 | constructor(product: Product?, quantity: BigDecimal) : this(UNDEFINED, product, quantity, product?.unitPrice) {} 43 | 44 | /** 45 | * Adds quantity of product in this LineItem. 46 | * @param amount amount for add in quantity. 47 | */ 48 | fun addQuantity(qty: BigDecimal) { 49 | this.quantity=this.quantity.add( qty) 50 | } 51 | 52 | fun didcutQuantity(qty: BigDecimal) { 53 | this.quantity=this.quantity.subtract( qty) 54 | } 55 | 56 | 57 | /** 58 | * Sets price product of this LineItem. 59 | * @param unitPriceAtSale price product of this LineItem. 60 | */ 61 | fun setUnitPriceAtSale(unitPriceAtSale: BigDecimal) { 62 | this.unitPriceAtSale = unitPriceAtSale 63 | } 64 | 65 | 66 | 67 | fun taxamount():BigDecimal?{ 68 | var tax:BigDecimal?= BigDecimal.ZERO 69 | 70 | if (product!!.is_tax_inclusive==false) { 71 | tax = (((unitPriceAtSale)!!.multiply(product!!.tax_percent.toBigDecimal())).divide(100.toBigDecimal())).multiply(quantity) 72 | }else{ 73 | // tax excluded price = item price / ((tax rate /100) + 1 ) 74 | var taxExcludedPrice=product?.unitPrice/((product?.tax_percent.toBigDecimal().divide(100.toBigDecimal()))+BigDecimal.ONE) 75 | var itemTaxt=product?.unitPrice?.subtract(taxExcludedPrice) 76 | tax=(itemTaxt).multiply(quantity) 77 | } 78 | return tax 79 | } 80 | 81 | /** 82 | * Determines whether two objects are equal or not. 83 | * @return true if Object is a LineItem with same ID ; otherwise false. 84 | */ 85 | override fun equals(`object`: Any?): Boolean { 86 | if (`object` == null) 87 | return false 88 | if (`object` !is LineItem) 89 | return false 90 | val lineItem = `object` as LineItem? 91 | return lineItem!!.id == this.id 92 | } 93 | 94 | companion object { 95 | 96 | /** 97 | * Static value for UNDEFINED ID. 98 | */ 99 | val UNDEFINED = -1 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /domain/inventory/Product.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.domain.inventory 2 | 3 | import java.math.BigDecimal 4 | import java.util.HashMap 5 | 6 | /** 7 | * Product or item represents the real product in store. 8 | * 9 | * @author Ionob Team 10 | */ 11 | open class Product 12 | /** 13 | * Constructs a new Product. 14 | * @param id ID of the product, This value should be assigned from database. 15 | * @param name name of this product. 16 | * @param barcode barcode (any standard format) of this product. 17 | * @param salePrice price for using when doing sale. 18 | * 19 | */ 20 | ( 21 | /** 22 | * Returns id of this product. 23 | * @return id of this product. 24 | */ 25 | val id: Int, 26 | /** 27 | * Returns name of this product. 28 | * @return name of this product. 29 | */ 30 | /** 31 | * Sets name of this product. 32 | * @param name name of this product. 33 | */ 34 | var name: String?, 35 | /** 36 | * Returns barcode of this product. 37 | * @return barcode of this product. 38 | */ 39 | /** 40 | * Sets product_id of this product. 41 | * @param productId barcode of this product. 42 | */ 43 | var productId: Int?, 44 | 45 | /** 46 | * Returns barcode of this product. 47 | * @return barcode of this product. 48 | */ 49 | /** 50 | * Sets barcode of this product. 51 | * @param barcode barcode of this product. 52 | */ 53 | 54 | var barcode: String?, 55 | /** 56 | * Returns price of this product. 57 | * @return price of this product. 58 | */ 59 | /** 60 | * Sets price of this product. 61 | * @param unitPrice price of this product. 62 | */ 63 | 64 | var unitPrice: BigDecimal, 65 | 66 | 67 | var stockQty: BigDecimal, 68 | 69 | var uom: String, 70 | 71 | var category_id: Int, 72 | 73 | var image: String, 74 | var tax_id: Int, 75 | 76 | var tax_percent: Double, 77 | 78 | var is_tax_inclusive: Boolean, 79 | 80 | var tax_amount: BigDecimal 81 | 82 | ) { 83 | 84 | /** 85 | * Constructs a new Product. 86 | * @param name name of this product. 87 | * @param barcode barcode (any standard format) of this product. 88 | * @param salePrice price for using when doing sale. 89 | */ 90 | constructor( 91 | name: String, 92 | productId: Int, 93 | barcode: String, 94 | salePrice: BigDecimal, 95 | stockQty: BigDecimal, 96 | uom: String, 97 | categori: Int, 98 | image: String, 99 | tax_id: Int, 100 | tax_percent:Double, 101 | tax_mode: Boolean, 102 | tax_amount: BigDecimal 103 | ) : this(UNDEFINED_ID, name, productId, barcode, salePrice, stockQty, uom, categori, image, tax_id, tax_percent, tax_mode, tax_amount) { 104 | } 105 | 106 | /** 107 | * Returns the description of this Product in Map format. 108 | * @return the description of this Product in Map format. 109 | */ 110 | fun toMap(): Map { 111 | val map = HashMap() 112 | map["id"] = id.toString() + "" 113 | map["name"] = name 114 | map["barcode"] = barcode 115 | map["unitPrice"] = unitPrice.toString() + "" 116 | return map 117 | 118 | } 119 | 120 | companion object { 121 | 122 | /** 123 | * Static value for UNDEFINED ID. 124 | */ 125 | val UNDEFINED_ID = -1 126 | } 127 | 128 | } 129 | -------------------------------------------------------------------------------- /domain/inventory/ProductCatalog.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.domain.inventory 2 | 3 | import com.ionob.pos.db.inventory.InventoryDao 4 | import java.math.BigDecimal 5 | 6 | /** 7 | * Book that keeps list of Product. 8 | * 9 | * @author Ionob Team 10 | */ 11 | class ProductCatalog 12 | /** 13 | * Constructs Data Access Object of inventory in ProductCatalog. 14 | * @param inventoryDao DAO of inventory. 15 | */ 16 | (private val inventoryDao: InventoryDao?) { 17 | 18 | /** 19 | * Returns list of all products in inventory. 20 | * @return list of all products in inventory. 21 | */ 22 | val allProduct: List? 23 | get() = inventoryDao?.allProduct 24 | 25 | /** 26 | * Constructs product and adds product to inventory. 27 | * @param name name of product. 28 | * @param barcode barcode of product. 29 | * @param salePrice price of product. 30 | * @return true if product adds in inventory success ; otherwise false. 31 | */ 32 | fun addProduct(name: String, 33 | product_id: Int 34 | , barcode: String, 35 | salePrice: BigDecimal 36 | , uom:String, 37 | stock:BigDecimal, 38 | category_id:Int, 39 | image:String, 40 | tax_id:Int, 41 | tax_percent:Double, 42 | is_included_tax:Boolean, 43 | tax_amount:BigDecimal): Boolean { 44 | val product = Product(name,product_id, barcode, salePrice, stock,uom,category_id,image,tax_id,tax_percent,is_included_tax,tax_amount) 45 | val id = inventoryDao?.addProduct(product) 46 | return id != -1 47 | } 48 | 49 | /** 50 | * Edits product. 51 | * @param product the product to be edited. 52 | * @return true if product edits success ; otherwise false. 53 | */ 54 | fun editProduct(product: Product?): Boolean? { 55 | val respond = inventoryDao?.editProduct(product) 56 | return respond 57 | } 58 | 59 | /** 60 | * Returns product from inventory finds by barcode. 61 | * @param barcode barcode of product. 62 | * @return product 63 | */ 64 | fun getProductByBarcode(barcode: String): Product? { 65 | return inventoryDao?.getProductByBarcode(barcode) 66 | } 67 | 68 | /** 69 | * Returns product from inventory finds by id. 70 | * @param id id of product. 71 | * @return product 72 | */ 73 | fun getProductById(id: Int): Product? { 74 | return inventoryDao?.getProductById(id) 75 | } 76 | 77 | /** 78 | * Returns list of product in inventory finds by name. 79 | * @param name name of product. 80 | * @return list of product in inventory finds by name. 81 | */ 82 | fun getProductByName(name: String): List? { 83 | return inventoryDao?.getProductByName(name) 84 | } 85 | 86 | /** 87 | * Search product from string in inventory. 88 | * @param search string for searching. 89 | * @return list of product. 90 | */ 91 | fun searchProduct(search: String): List? { 92 | return inventoryDao?.searchProduct(search) 93 | } 94 | 95 | /** 96 | * Clears ProductCatalog. 97 | */ 98 | fun clearProductCatalog() { 99 | inventoryDao?.clearProductCatalog() 100 | } 101 | 102 | /** 103 | * Hidden product from inventory. 104 | * @param product The product to be hidden. 105 | */ 106 | fun suspendProduct(product: Product?) { 107 | inventoryDao?.suspendProduct(product) 108 | } 109 | 110 | 111 | } 112 | -------------------------------------------------------------------------------- /domain/inventory/ProductLot.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.domain.inventory 2 | 3 | import java.util.HashMap 4 | 5 | import com.ionob.pos.domain.DateTimeStrategy 6 | 7 | /** 8 | * Lot or bunch of product that import to inventory. 9 | * 10 | * @author Ionob Team 11 | */ 12 | class ProductLot 13 | /** 14 | * Constructs a new ProductLot. 15 | * @param id ID of the ProductLot, This value should be assigned from database. 16 | * @param dateAdded date and time of adding this lot. 17 | * @param quantity quantity of product. 18 | * @param product a product of this lot. 19 | * @param unitCost cost (of buy) of each unit in this lot. 20 | */ 21 | ( 22 | /** 23 | * Returns id of this ProductLot. 24 | * @return id of this ProductLot. 25 | */ 26 | val id: Int, 27 | /** 28 | * Returns date added of this ProductLot. 29 | * @return date added of this ProductLot. 30 | */ 31 | val dateAdded: String, 32 | /** 33 | * Returns quantity of this ProductLot. 34 | * @return quantity of this ProductLot. 35 | */ 36 | val quantity: Int, 37 | /** 38 | * Returns product in this ProductLot. 39 | * @return product in this ProductLot. 40 | */ 41 | val product: Product?, private val unitCost: Double) { 42 | 43 | /** 44 | * Returns cost of this ProductLot. 45 | * @return cost of this ProductLot. 46 | */ 47 | fun unitCost(): Double { 48 | return unitCost 49 | } 50 | 51 | /** 52 | * Returns the description of this ProductLot in Map format. 53 | * @return the description of this ProductLot in Map format. 54 | */ 55 | fun toMap(): Map { 56 | val map = HashMap() 57 | map["id"] = id.toString() + "" 58 | map["dateAdded"] = DateTimeStrategy.format(dateAdded) 59 | map["quantity"] = quantity.toString() + "" 60 | map["productName"] = product?.name 61 | map["cost"] = unitCost.toString() + "" 62 | return map 63 | } 64 | 65 | companion object { 66 | 67 | /** 68 | * Static value for UNDEFINED ID. 69 | */ 70 | val UNDEFINED_ID = -1 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /domain/inventory/Stock.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.domain.inventory 2 | 3 | import com.ionob.pos.db.inventory.InventoryDao 4 | import java.math.BigDecimal 5 | 6 | /** 7 | * Import log of ProductLot come in to store. 8 | * 9 | * @author Ionob Team 10 | */ 11 | class Stock 12 | /** 13 | * Constructs Data Access Object of inventory in ProductCatalog. 14 | * @param inventoryDao DAO of inventory. 15 | */ 16 | (private val inventoryDao: InventoryDao?) { 17 | 18 | /** 19 | * Returns all ProductLots in inventory. 20 | * @return all ProductLots in inventory. 21 | */ 22 | val allProductLot: List? 23 | get() = inventoryDao?.allProductLot 24 | 25 | /** 26 | * Constructs ProductLot and adds ProductLot to inventory. 27 | * @param dateAdded date added of ProductLot. 28 | * @param quantity quantity of ProductLot. 29 | * @param product product of ProductLot. 30 | * @param cost cost of ProductLot. 31 | * @return 32 | */ 33 | fun addProductLot(dateAdded: String, quantity: Int, product: Product?, cost: Double): Boolean { 34 | val productLot = ProductLot(ProductLot.UNDEFINED_ID, dateAdded, quantity, product, cost) 35 | val id = inventoryDao?.addProductLot(productLot) 36 | return id != -1 37 | } 38 | 39 | /** 40 | * Returns list of ProductLot in inventory finds by id. 41 | * @param id id of ProductLot. 42 | * @return list of ProductLot in inventory finds by id. 43 | */ 44 | fun getProductLotByProductId(id: Int): List? { 45 | return inventoryDao?.getProductLotByProductId(id) 46 | } 47 | 48 | /** 49 | * Returns Stock in inventory finds by id. 50 | * @param id id of Stock. 51 | * @return Stock in inventory finds by id. 52 | */ 53 | fun getStockSumById(id: Int): Int? { 54 | return inventoryDao?.getStockSumById(id) 55 | } 56 | 57 | /** 58 | * Updates quantity of product. 59 | * @param productId id of product. 60 | * @param quantity quantity of product. 61 | */ 62 | fun updateStockSum(productId: Int?, quantity: BigDecimal) { 63 | inventoryDao?.updateStockSum(productId, quantity.toDouble()) 64 | 65 | } 66 | 67 | /** 68 | * Clear Stock. 69 | */ 70 | fun clearStock() { 71 | inventoryDao?.clearStock() 72 | 73 | } 74 | 75 | 76 | } 77 | -------------------------------------------------------------------------------- /domain/sale/QuickLoadSale.java: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.domain.sale; 2 | 3 | import java.math.BigDecimal; 4 | 5 | /** 6 | * Sale that loads only total and orders. 7 | * It's for overview report that doesn't need LineItem's information. 8 | * NOTE: This Sale instance throws NullPointerException 9 | * when calling method that involve with LineItem. 10 | * 11 | * @author Ionob Team 12 | * 13 | */ 14 | public class QuickLoadSale extends Sale { 15 | 16 | private BigDecimal total; 17 | private BigDecimal orders; 18 | 19 | /** 20 | * 21 | * @param id ID of this sale. 22 | * @param startTime 23 | * @param endTime 24 | * @param status 25 | * @param total 26 | * @param orders numbers of lineItem in this Sale. 27 | */ 28 | public QuickLoadSale(int id, String startTime, String endTime, String status, BigDecimal total, BigDecimal orders) { 29 | super(id, startTime, endTime, status); 30 | this.total = total; 31 | this.orders = orders; 32 | } 33 | 34 | @Override 35 | public BigDecimal getOrders() { 36 | return orders; 37 | } 38 | 39 | @Override 40 | public BigDecimal getTotal() { 41 | return total; 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /domain/sale/Register.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.domain.sale 2 | 3 | import com.ionob.pos.domain.DateTimeStrategy 4 | import com.ionob.pos.domain.inventory.Inventory 5 | import com.ionob.pos.domain.inventory.LineItem 6 | import com.ionob.pos.domain.inventory.Product 7 | import com.ionob.pos.domain.inventory.Stock 8 | import com.ionob.pos.db.NoDaoSetException 9 | import com.ionob.pos.db.sale.SaleDao 10 | import java.math.BigDecimal 11 | 12 | 13 | class Register @Throws(NoDaoSetException::class) 14 | private constructor() { 15 | 16 | private var currentSale: Sale? = null 17 | var salesRecordTemplate:Sale?=null 18 | 19 | /** 20 | * Returns total price of Sale. 21 | * @return total price of Sale. 22 | */ 23 | val total: BigDecimal 24 | get() = if (currentSale == null) BigDecimal.ZERO else currentSale!!.total 25 | 26 | val totalDiscount:BigDecimal 27 | get() = if (currentSale == null) BigDecimal.ZERO else currentSale!!.totalDiscount 28 | 29 | 30 | val totaltax:BigDecimal 31 | get() = if (currentSale == null) BigDecimal.ZERO else currentSale!!.totaltax 32 | 33 | 34 | 35 | init { 36 | if (!isDaoSet) { 37 | throw NoDaoSetException() 38 | } 39 | stock = Inventory.getInstance().getStock() 40 | 41 | } 42 | 43 | /** 44 | * Initiates a new Sale. 45 | * @param startTime time that sale created. 46 | * @return Sale that created. 47 | */ 48 | fun initiateSale(sale: Sale): Sale { 49 | if (currentSale != null) { 50 | return currentSale as Sale 51 | } 52 | currentSale = saleDao!!.initiateSale(sale!!) 53 | return currentSale as Sale 54 | } 55 | 56 | /** 57 | * Add Product to Sale. 58 | * @param product product to be added. 59 | * @param quantity quantity of product that added. 60 | * @return LineItem of Sale that just added. 61 | */ 62 | fun addItem(product: Product?, quantity: BigDecimal): LineItem { 63 | 64 | if (product!!.is_tax_inclusive==true) { 65 | // tax excluded price = item price / ((tax rate /100) + 1 ) 66 | var taxExcludedPrice=product?.unitPrice/((product?.tax_percent.toBigDecimal().divide(100.toBigDecimal()))+BigDecimal.ONE) 67 | product?.unitPrice=taxExcludedPrice 68 | var itemTaxt=product?.unitPrice?.subtract(taxExcludedPrice) 69 | product?.tax_amount=itemTaxt 70 | } 71 | if (currentSale == null) { 72 | initiateSale(salesRecordTemplate!!) 73 | 74 | } 75 | 76 | val lineItem = currentSale!!.addLineItem(product!!, quantity) 77 | 78 | if (lineItem.id == LineItem.UNDEFINED) { 79 | val lineId = saleDao!!.addLineItem(currentSale!!.id, lineItem) 80 | lineItem.id = lineId 81 | } else { 82 | saleDao!!.updateLineItem(currentSale!!.id, lineItem) 83 | } 84 | 85 | return lineItem 86 | } 87 | 88 | fun getSalesLine(salesID:Int,lineID:Int):LineItem? 89 | { 90 | return saleDao!!.getLine(salesID,lineID) 91 | } 92 | 93 | /** 94 | * End the Sale. 95 | * @param endTime time that Sale ended. 96 | */ 97 | fun endSale(endTime: String) { 98 | if (currentSale != null) { 99 | saleDao!!.endSale(currentSale!!, endTime) 100 | for (line in currentSale!!.allLineItem) { 101 | stock!!.updateStockSum(line.product!!.productId, line.quantity) 102 | } 103 | currentSale = null 104 | } 105 | } 106 | 107 | /** 108 | * Returns the current Sale of this Register. 109 | * @return the current Sale of this Register. 110 | */ 111 | fun getCurrentSale(): Sale? { 112 | if (currentSale == null) 113 | initiateSale(salesRecordTemplate!!) 114 | return currentSale 115 | } 116 | 117 | /** 118 | * Sets the current Sale of this Register. 119 | * @param id of Sale to retrieve. 120 | * @return true if success to load Sale from ID; otherwise false. 121 | */ 122 | fun setCurrentSale(id: Int): Boolean { 123 | currentSale = saleDao!!.getSaleById(id) 124 | return false 125 | } 126 | 127 | fun setCurrentSalesNull() { 128 | currentSale = null 129 | } 130 | 131 | 132 | /** 133 | * Determines that if there is a Sale handling or not. 134 | * @return true if there is a current Sale; otherwise false. 135 | */ 136 | fun hasSale(): Boolean { 137 | return if (currentSale == null) false else true 138 | } 139 | 140 | /** 141 | * Cancels the current Sale. 142 | */ 143 | fun cancleSale() { 144 | if (currentSale != null) { 145 | saleDao!!.cancelSale(currentSale!!, DateTimeStrategy.currentTime) 146 | currentSale = null 147 | } 148 | } 149 | 150 | /** 151 | * Edit the specific LineItem 152 | * @param saleId ID of LineItem to be edited. 153 | * @param lineItem LineItem to be edited. 154 | * @param quantity a new quantity to set. 155 | * @param priceAtSale a new priceAtSale to set. 156 | */ 157 | fun updateItem(saleId: Int, lineItem: LineItem, quantity: BigDecimal, priceAtSale: BigDecimal) { 158 | lineItem.setUnitPriceAtSale(priceAtSale) 159 | lineItem.quantity = quantity 160 | saleDao!!.updateLineItem(saleId, lineItem) 161 | } 162 | 163 | /** 164 | * Removes LineItem from the current Sale. 165 | * @param lineItem lineItem to be removed. 166 | */ 167 | fun removeItem(lineItem: LineItem) { 168 | saleDao!!.removeLineItem(lineItem.id) 169 | currentSale!!.removeItem(lineItem) 170 | if (currentSale!!.allLineItem.isEmpty()) { 171 | cancleSale() 172 | } 173 | } 174 | 175 | companion object { 176 | private var instance: Register? = null 177 | private var saleDao: SaleDao? = null 178 | private var stock: Stock? = null 179 | 180 | /** 181 | * Determines whether the DAO already set or not. 182 | * @return true if the DAO already set; otherwise false. 183 | */ 184 | val isDaoSet: Boolean 185 | get() = saleDao != null 186 | 187 | @Throws(NoDaoSetException::class) 188 | internal fun getInstance(): Register { 189 | if (instance == null) instance = Register() 190 | return instance as Register 191 | } 192 | 193 | /** 194 | * Injects its sale DAO 195 | * @param dao DAO of sale 196 | */ 197 | internal fun setSaleDao(dao: SaleDao) { 198 | saleDao = dao 199 | } 200 | } 201 | 202 | } -------------------------------------------------------------------------------- /domain/sale/Sale.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.domain.sale 2 | 3 | import java.math.BigDecimal 4 | import java.util.ArrayList 5 | 6 | import com.ionob.pos.domain.inventory.LineItem 7 | import com.ionob.pos.domain.inventory.Product 8 | 9 | /** 10 | * Sale represents sale operation. 11 | * 12 | * @author Ionob Team 13 | */ 14 | open class Sale 15 | /** 16 | * Constructs a new Sale. 17 | * @param id ID of this Sale. 18 | * @param startTime start time of this Sale. 19 | * @param endTime end time of this Sale. 20 | * @param status status of this Sale. 21 | * @param items list of LineItem in this Sale. 22 | */ 23 | @JvmOverloads constructor(var id: Int, var startTime: String, var endTime: String = startTime, var status: String ?= "" 24 | , private var items: MutableList = ArrayList()) { 25 | var customerCode: String? = null 26 | var customerId: Int? = null 27 | var salesRep: String? = null 28 | var invoiceDate: String? = null 29 | var invoiceNo: String? = null 30 | var profileId: Int? = null 31 | var subTotal: BigDecimal? = null 32 | var grandTotal: BigDecimal? = null 33 | var discountAmountt: BigDecimal? = null 34 | var lineDiscount: BigDecimal? = null 35 | var isChecked: Boolean? = null 36 | var bpLocationId: Int? = null 37 | var remoteRecordId: Int? = null 38 | var isPurchase: Boolean? = null 39 | var priceListId:Int? = null 40 | var roundOff: BigDecimal? = null 41 | var errorMessage: String? = null 42 | var amountPaid: BigDecimal? = BigDecimal.ZERO 43 | var paymentType: String? =null 44 | var referenceNumber: String? =null 45 | /** 46 | * Returns list of LineItem in this Sale. 47 | * @return list of LineItem in this Sale. 48 | */ 49 | val allLineItem: List 50 | get() = items 51 | 52 | /** 53 | * Returns the total price of this Sale. 54 | * @return the total price of this Sale. 55 | */ 56 | open val total: BigDecimal 57 | get() { 58 | var amount = BigDecimal.ZERO 59 | for (lineItem in items) { 60 | amount = amount.add(lineItem.totalAmount) 61 | } 62 | return amount 63 | } 64 | 65 | open val totalDiscount: BigDecimal 66 | get() { 67 | var discount = BigDecimal.ZERO 68 | for (lineItem in items) { 69 | discount = discount.add(lineItem.discount) 70 | } 71 | return discount 72 | } 73 | open val totaltax: BigDecimal 74 | get() { 75 | var taxwholeamount = BigDecimal.ZERO 76 | for (lineItem in items) { 77 | taxwholeamount = taxwholeamount.add(lineItem.totalTax) 78 | } 79 | return taxwholeamount 80 | } 81 | 82 | /** 83 | * Returns the total quantity of this Sale. 84 | * @return the total quantity of this Sale. 85 | */ 86 | open val orders: BigDecimal 87 | get() { 88 | var orderCount = BigDecimal.ZERO 89 | for (lineItem in items) { 90 | orderCount = orderCount.add(lineItem.quantity) 91 | } 92 | return orderCount 93 | } 94 | 95 | /** 96 | * Add Product to Sale. 97 | * @param product product to be added. 98 | * @param quantity quantity of product that added. 99 | * @return LineItem of Sale that just added. 100 | */ 101 | fun addLineItem(product: Product, quantity: BigDecimal): LineItem { 102 | 103 | for (lineItem in items) { 104 | if (lineItem.product!!.productId == product.productId) { 105 | lineItem.quantity=(quantity) 106 | return lineItem 107 | } 108 | } 109 | 110 | val lineItem = LineItem(product, quantity) 111 | items.add(lineItem) 112 | return lineItem 113 | } 114 | 115 | fun size(): Int { 116 | return items.size 117 | } 118 | 119 | /** 120 | * Returns a LineItem with specific index. 121 | * @param index of specific LineItem. 122 | * @return a LineItem with specific index. 123 | */ 124 | fun getLineItemAt(index: Int): LineItem? { 125 | return if (index >= 0 && index < items.size) items[index] else null 126 | } 127 | 128 | /** 129 | * Returns the description of this Sale in Map format. 130 | * @return the description of this Sale in Map format. 131 | */ 132 | // fun toMap(): Map { 133 | // val map = HashMap() 134 | // map["id"] = id.toString() + "" 135 | // map["startTime"] = startTime 136 | // map["endTime"] = endTime 137 | // map["status"] = status 138 | // map["total"] = total + "" 139 | // map["orders"] = orders + "" 140 | // 141 | // return map 142 | // } 143 | 144 | /** 145 | * Removes LineItem from Sale. 146 | * @param lineItem lineItem to be removed. 147 | */ 148 | fun removeItem(lineItem: LineItem) { 149 | items.remove(lineItem) 150 | } 151 | 152 | } -------------------------------------------------------------------------------- /domain/sale/SaleLedger.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.domain.sale 2 | 3 | import java.util.Calendar 4 | 5 | import com.ionob.pos.db.NoDaoSetException 6 | import com.ionob.pos.db.sale.SaleDao 7 | 8 | /** 9 | * Book that keeps sale record. 10 | * 11 | * @author Ionob Team 12 | */ 13 | class SaleLedger @Throws(NoDaoSetException::class) 14 | private constructor() { 15 | 16 | /** 17 | * Returns all sale in the records. 18 | * @return all sale in the records. 19 | */ 20 | val allSale: List 21 | get() = saleDao!!.allCompletedSale 22 | 23 | init { 24 | if (!isDaoSet) { 25 | throw NoDaoSetException() 26 | } 27 | } 28 | 29 | /** 30 | * Returns the Sale with specific ID. 31 | * @param id ID of specific Sale. 32 | * @return the Sale with specific ID. 33 | */ 34 | fun getSaleById(id: Int): Sale { 35 | return saleDao!!.getSaleById(id) 36 | } 37 | 38 | /** 39 | * Clear all records in SaleLedger. 40 | */ 41 | fun clearSaleLedger() { 42 | saleDao!!.clearSaleLedger() 43 | } 44 | 45 | /** 46 | * Returns list of Sale with scope of time. 47 | * @param start start bound of scope. 48 | * @param end end bound of scope. 49 | * @return list of Sale with scope of time. 50 | */ 51 | fun getAllSaleDuring(start: Calendar, end: Calendar): List { 52 | return saleDao!!.getAllSaleDuring(start, end) 53 | } 54 | 55 | companion object { 56 | 57 | private var instance: SaleLedger? = null 58 | private var saleDao: SaleDao? = null 59 | 60 | /** 61 | * Determines whether the DAO already set or not. 62 | * @return true if the DAO already set; otherwise false. 63 | */ 64 | val isDaoSet: Boolean 65 | get() = saleDao != null 66 | 67 | @Throws(NoDaoSetException::class) 68 | internal fun getInstance(): SaleLedger { 69 | if (instance == null) instance = SaleLedger() 70 | return instance as SaleLedger 71 | } 72 | 73 | /** 74 | * Sets the database connector. 75 | * @param dao Data Access Object of Sale. 76 | */ 77 | internal fun setSaleDao(dao: SaleDao) { 78 | saleDao = dao 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /domain/sale/SalesRcord.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.domain.sale 2 | 3 | import java.util.Calendar 4 | 5 | import com.ionob.pos.db.NoDaoSetException 6 | import com.ionob.pos.db.sale.SaleDao 7 | 8 | /** 9 | * Book that keeps sale record. 10 | * 11 | * @author Ionob Team 12 | */ 13 | class SalesRcord @Throws(NoDaoSetException::class) 14 | private constructor() { 15 | 16 | /** 17 | * Returns all sale in the records. 18 | * @return all sale in the records. 19 | */ 20 | val allSale: List 21 | get() = saleDao!!.allSale 22 | 23 | val allDraft: List 24 | get() = saleDao!!.allDraftSale 25 | 26 | val allCompleted: List 27 | get() = saleDao!!.allCompletedSale 28 | 29 | val allSynced: List 30 | get() = saleDao!!.allSynced 31 | 32 | val allFailed: List 33 | get() = saleDao!!.allFailed 34 | 35 | fun getCount(status:String):Int { 36 | return saleDao!!.getCoutOfRecord(status) 37 | } 38 | 39 | 40 | init { 41 | if (!isDaoSet) { 42 | throw NoDaoSetException() 43 | } 44 | } 45 | 46 | /** 47 | * Returns the Sale with specific ID. 48 | * @param id ID of specific Sale. 49 | * @return the Sale with specific ID. 50 | */ 51 | fun getSaleRcordById(id: Int): Sale { 52 | return saleDao!!.getSaleById(id) 53 | } 54 | 55 | /** 56 | * Clear all records in SaleLedger. 57 | */ 58 | fun clearSaleLedger() { 59 | saleDao!!.clearSaleLedger() 60 | } 61 | 62 | fun deleteSalesRecord(salesId:Int) { 63 | saleDao!!.deleteSalesRecord(salesId) 64 | } 65 | 66 | 67 | /** 68 | * Returns list of Sale with scope of time. 69 | * @param start start bound of scope. 70 | * @param end end bound of scope. 71 | * @return list of Sale with scope of time. 72 | */ 73 | fun getAllSaleDuring(start: Calendar, end: Calendar): List { 74 | return saleDao!!.getAllSaleDuring(start, end) 75 | } 76 | 77 | companion object { 78 | 79 | private var instance: SalesRcord? = null 80 | private var saleDao: SaleDao? = null 81 | 82 | /** 83 | * Determines whether the DAO already set or not. 84 | * @return true if the DAO already set; otherwise false. 85 | */ 86 | val isDaoSet: Boolean 87 | get() = saleDao != null 88 | 89 | @Throws(NoDaoSetException::class) 90 | internal fun getInstance(): SalesRcord { 91 | if (instance == null) instance = SalesRcord() 92 | return instance as SalesRcord 93 | } 94 | 95 | /** 96 | * Sets the database connector. 97 | * @param dao Data Access Object of Sale. 98 | */ 99 | internal fun setSaleDao(dao: SaleDao) { 100 | saleDao = dao 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /mcposprivacy.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Privacy Policy 7 | 8 | 9 | 10 | Privacy Policy

11 | mycodlabs.com built the MC POS app as 12 | a Free app. This SERVICE is provided by 13 | mycodlabs.com at no cost and is intended for use as 14 | is. 15 |

16 | This page is used to inform visitors regarding our 17 | policies with the collection, use, and disclosure of Personal 18 | Information if anyone decided to use our Service. 19 |

20 | If you choose to use our Service, then you agree to 21 | the collection and use of information in relation to this 22 | policy. The Personal Information that we collect is 23 | used for providing and improving the Service. We will not use or share your information with 24 | anyone except as described in this Privacy Policy. 25 |

26 | The terms used in this Privacy Policy have the same meanings 27 | as in our Terms and Conditions, which are accessible at 28 | MC POS unless otherwise defined in this Privacy Policy. 29 |

Information Collection and Use

30 | For a better experience, while using our Service, we 31 | may require you to provide us with certain personally 32 | identifiable information, including but not limited to Email ,User Name. The information that 33 | we request will be retained by us and used as described in this privacy policy. 34 |

35 | The app does use third-party services that may collect 36 | information used to identify you. 37 |

38 | Link to the privacy policy of third-party service providers used 39 | by the app 40 |

Log Data

41 | We want to inform you that whenever you 42 | use our Service, in a case of an error in the app 43 | we collect data and information (through third-party 44 | products) on your phone called Log Data. This Log Data may 45 | include information such as your device Internet Protocol 46 | (“IP”) address, device name, operating system version, the 47 | configuration of the app when utilizing our Service, 48 | the time and date of your use of the Service, and other 49 | statistics. 50 |

Cookies

51 | Cookies are files with a small amount of data that are 52 | commonly used as anonymous unique identifiers. These are sent 53 | to your browser from the websites that you visit and are 54 | stored on your device's internal memory. 55 |

56 | This Service does not use these “cookies” explicitly. However, 57 | the app may use third-party code and libraries that use 58 | “cookies” to collect information and improve their services. 59 | You have the option to either accept or refuse these cookies 60 | and know when a cookie is being sent to your device. If you 61 | choose to refuse our cookies, you may not be able to use some 62 | portions of this Service. 63 |

Service Providers

64 | We may employ third-party companies and 65 | individuals due to the following reasons: 66 |

  • To facilitate our Service;
  • To provide the Service on our behalf;
  • To perform Service-related services; or
  • To assist us in analyzing how our Service is used.

67 | We want to inform users of this Service 68 | that these third parties have access to their Personal 69 | Information. The reason is to perform the tasks assigned to 70 | them on our behalf. However, they are obligated not to 71 | disclose or use the information for any other purpose. 72 |

Security

73 | We value your trust in providing us your 74 | Personal Information, thus we are striving to use commercially 75 | acceptable means of protecting it. But remember that no method 76 | of transmission over the internet, or method of electronic 77 | storage is 100% secure and reliable, and we cannot 78 | guarantee its absolute security. 79 |

Links to Other Sites

80 | This Service may contain links to other sites. If you click on 81 | a third-party link, you will be directed to that site. Note 82 | that these external sites are not operated by us. 83 | Therefore, we strongly advise you to review the 84 | Privacy Policy of these websites. We have 85 | no control over and assume no responsibility for the content, 86 | privacy policies, or practices of any third-party sites or 87 | services. 88 |

Children’s Privacy

89 | These Services do not address anyone under the age of 13. 90 | We do not knowingly collect personally 91 | identifiable information from children under 13 years of age. In the case 92 | we discover that a child under 13 has provided 93 | us with personal information, we immediately 94 | delete this from our servers. If you are a parent or guardian 95 | and you are aware that your child has provided us with 96 | personal information, please contact us so that 97 | we will be able to do the necessary actions. 98 |

Changes to This Privacy Policy

99 | We may update our Privacy Policy from 100 | time to time. Thus, you are advised to review this page 101 | periodically for any changes. We will 102 | notify you of any changes by posting the new Privacy Policy on 103 | this page. 104 |

This policy is effective as of 2023-08-19

Contact Us

105 | If you have any questions or suggestions about our 106 | Privacy Policy, do not hesitate to contact us at anycodeslabs@gmail.com. 107 |

websites Download App

108 | 109 | 110 | -------------------------------------------------------------------------------- /print/MainActivityPrint.kt: -------------------------------------------------------------------------------- 1 | package suman.com.andoirdbluetoothprint 2 | 3 | 4 | import java.io.IOException 5 | import java.io.OutputStream 6 | import java.nio.ByteBuffer 7 | import java.util.UUID 8 | 9 | import android.app.Activity 10 | import android.app.ProgressDialog 11 | import android.bluetooth.BluetoothAdapter 12 | import android.bluetooth.BluetoothDevice 13 | import android.bluetooth.BluetoothSocket 14 | import android.content.Intent 15 | import android.os.Bundle 16 | import android.os.Handler 17 | import android.os.Message 18 | import android.util.Log 19 | import android.view.View 20 | import android.widget.Button 21 | import android.widget.Toast 22 | import com.ionob.pos.R 23 | import kotlinx.android.synthetic.main.print_preview.* 24 | import kotlinx.android.synthetic.main.print_preview.view.* 25 | 26 | 27 | class MainActivityPrint : Activity() { 28 | internal lateinit var mScan: Button 29 | internal lateinit var mPrint: Button 30 | internal lateinit var mDisc: Button 31 | internal var mBluetoothAdapter: BluetoothAdapter? = null 32 | private val applicationUUID = UUID 33 | .fromString("00001101-0000-1000-8000-00805F9B34FB") 34 | private var mBluetoothConnectProgressDialog: ProgressDialog? = null 35 | private var mBluetoothSocket: BluetoothSocket? = null 36 | 37 | 38 | public override fun onCreate(mSavedInstanceState: Bundle?) { 39 | super.onCreate(mSavedInstanceState) 40 | setContentView(R.layout.print_preview) 41 | var BILL = "" 42 | 43 | BILL = (" INOB Softwares \n"+ 44 | " Calicut India \n"+ 45 | " www.ionob.com \n") 46 | BILL = BILL + "-----------------------------------------------\n" 47 | 48 | 49 | BILL = BILL + String.format("%1$-10s %2$10s %3$13s %4$10s", "Item", "Qty", "Rate", "Totel") 50 | BILL = BILL + "\n" 51 | BILL = BILL + "-----------------------------------------------" 52 | BILL = BILL + "\n " + String.format("%1$-10s %2$10s %3$11s %4$10s", "item-001", "5", "10", "50.00") 53 | BILL = BILL + "\n " + String.format("%1$-10s %2$10s %3$11s %4$10s", "item-002", "10", "5", "50.00") 54 | BILL = BILL + "\n " + String.format("%1$-10s %2$10s %3$11s %4$10s", "item-003", "20", "10", "200.00") 55 | BILL = BILL + "\n " + String.format("%1$-10s %2$10s %3$11s %4$10s", "item-004", "50", "10", "500.00") 56 | 57 | BILL = BILL + "\n-----------------------------------------------" 58 | BILL = BILL + "\n\n " 59 | 60 | BILL = BILL + " Total Qty:" + " " + "85" + "\n" 61 | BILL = BILL + " Total Value:" + " " + "700.00" + "\n" 62 | 63 | BILL = BILL + "-----------------------------------------------\n" 64 | BILL = BILL + "\n\n " 65 | // os.write(BILL.toByteArray()) 66 | // //This is printer specific code you can comment ==== > Start 67 | // 68 | // // Setting height 69 | // val gs = 29 70 | // os.write(intToByteArray(gs).toInt()) 71 | // val h = 104 72 | // os.write(intToByteArray(h).toInt()) 73 | // val n = 162 74 | // os.write(intToByteArray(n).toInt()) 75 | // 76 | // // Setting Width 77 | // val gs_width = 29 78 | // os.write(intToByteArray(gs_width).toInt()) 79 | // val w = 119 80 | // os.write(intToByteArray(w).toInt()) 81 | // val n_width = 2 82 | // os.write(intToByteArray(n_width).toInt()) 83 | 84 | 85 | 86 | 87 | print_preview.text=BILL 88 | }// onCreate 89 | 90 | 91 | 92 | override fun onBackPressed() { 93 | 94 | finish() 95 | } 96 | 97 | 98 | } 99 | -------------------------------------------------------------------------------- /print/UnicodeFormatter.java: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.print; 2 | 3 | 4 | 5 | public class UnicodeFormatter { 6 | 7 | static public String byteToHex(byte b) { 8 | // Returns hex String representation of byte b 9 | char hexDigit[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 10 | 'a', 'b', 'c', 'd', 'e', 'f' }; 11 | char[] array = { hexDigit[(b >> 4) & 0x0f], hexDigit[b & 0x0f] }; 12 | return new String(array); 13 | } 14 | 15 | static public String charToHex(char c) { 16 | // Returns hex String representation of char c 17 | byte hi = (byte) (c >>> 8); 18 | byte lo = (byte) (c & 0xff); 19 | return byteToHex(hi) + byteToHex(lo); 20 | } 21 | 22 | } // class 23 | -------------------------------------------------------------------------------- /settings/AppCompatPreferenceActivity.java: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.settings; 2 | 3 | import android.content.res.Configuration; 4 | import android.os.Bundle; 5 | import android.preference.PreferenceActivity; 6 | import android.support.annotation.LayoutRes; 7 | import android.support.annotation.Nullable; 8 | import android.support.v7.app.ActionBar; 9 | import android.support.v7.app.AppCompatDelegate; 10 | import android.support.v7.widget.Toolbar; 11 | import android.view.MenuInflater; 12 | import android.view.View; 13 | import android.view.ViewGroup; 14 | 15 | /** 16 | * A {@link android.preference.PreferenceActivity} which implements and proxies the necessary calls 17 | * to be used with AppCompat. 18 | */ 19 | public abstract class AppCompatPreferenceActivity extends PreferenceActivity { 20 | 21 | private AppCompatDelegate mDelegate; 22 | 23 | @Override 24 | protected void onCreate(Bundle savedInstanceState) { 25 | getDelegate().installViewFactory(); 26 | getDelegate().onCreate(savedInstanceState); 27 | super.onCreate(savedInstanceState); 28 | } 29 | 30 | @Override 31 | protected void onPostCreate(Bundle savedInstanceState) { 32 | super.onPostCreate(savedInstanceState); 33 | getDelegate().onPostCreate(savedInstanceState); 34 | } 35 | 36 | public ActionBar getSupportActionBar() { 37 | return getDelegate().getSupportActionBar(); 38 | } 39 | 40 | public void setSupportActionBar(@Nullable Toolbar toolbar) { 41 | getDelegate().setSupportActionBar(toolbar); 42 | } 43 | 44 | @Override 45 | public MenuInflater getMenuInflater() { 46 | return getDelegate().getMenuInflater(); 47 | } 48 | 49 | @Override 50 | public void setContentView(@LayoutRes int layoutResID) { 51 | getDelegate().setContentView(layoutResID); 52 | } 53 | 54 | @Override 55 | public void setContentView(View view) { 56 | getDelegate().setContentView(view); 57 | } 58 | 59 | @Override 60 | public void setContentView(View view, ViewGroup.LayoutParams params) { 61 | getDelegate().setContentView(view, params); 62 | } 63 | 64 | @Override 65 | public void addContentView(View view, ViewGroup.LayoutParams params) { 66 | getDelegate().addContentView(view, params); 67 | } 68 | 69 | @Override 70 | protected void onPostResume() { 71 | super.onPostResume(); 72 | getDelegate().onPostResume(); 73 | } 74 | 75 | @Override 76 | protected void onTitleChanged(CharSequence title, int color) { 77 | super.onTitleChanged(title, color); 78 | getDelegate().setTitle(title); 79 | } 80 | 81 | @Override 82 | public void onConfigurationChanged(Configuration newConfig) { 83 | super.onConfigurationChanged(newConfig); 84 | getDelegate().onConfigurationChanged(newConfig); 85 | } 86 | 87 | @Override 88 | protected void onStop() { 89 | super.onStop(); 90 | getDelegate().onStop(); 91 | } 92 | 93 | @Override 94 | protected void onDestroy() { 95 | super.onDestroy(); 96 | getDelegate().onDestroy(); 97 | } 98 | 99 | public void invalidateOptionsMenu() { 100 | getDelegate().invalidateOptionsMenu(); 101 | } 102 | 103 | private AppCompatDelegate getDelegate() { 104 | if (mDelegate == null) { 105 | mDelegate = AppCompatDelegate.create(this, null); 106 | } 107 | return mDelegate; 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /settings/MainSettingsActivity.java: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.settings; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.support.v7.widget.Toolbar; 7 | import android.view.Menu; 8 | import android.view.MenuItem; 9 | 10 | import com.ionob.pos.R; 11 | 12 | public class MainSettingsActivity extends AppCompatActivity { 13 | 14 | int SETTINGS=0X10; 15 | @Override 16 | protected void onCreate(Bundle savedInstanceState) { 17 | super.onCreate(savedInstanceState); 18 | setContentView(R.layout.activity_settings_main); 19 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 20 | setSupportActionBar(toolbar); 21 | startActivityForResult(new Intent(MainSettingsActivity.this, SettingsActivity.class),SETTINGS); 22 | } 23 | 24 | @Override 25 | public boolean onCreateOptionsMenu(Menu menu) { 26 | return true; 27 | } 28 | 29 | @Override 30 | public boolean onOptionsItemSelected(MenuItem item) { 31 | int id = item.getItemId(); 32 | 33 | 34 | return super.onOptionsItemSelected(item); 35 | } 36 | 37 | @Override 38 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 39 | super.onActivityResult(requestCode, resultCode, data); 40 | if(requestCode==SETTINGS&&resultCode==RESULT_OK) 41 | { 42 | super.onBackPressed(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /settings/SettingsActivity.java: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.settings; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.content.pm.PackageManager; 6 | import android.media.Ringtone; 7 | import android.media.RingtoneManager; 8 | import android.net.Uri; 9 | import android.os.Build; 10 | import android.os.Bundle; 11 | import android.preference.EditTextPreference; 12 | import android.preference.ListPreference; 13 | import android.preference.Preference; 14 | import android.preference.PreferenceFragment; 15 | import android.preference.PreferenceManager; 16 | import android.preference.RingtonePreference; 17 | import android.text.TextUtils; 18 | import android.view.MenuItem; 19 | 20 | import com.ionob.pos.R; 21 | 22 | public class SettingsActivity extends AppCompatPreferenceActivity { 23 | private static final String TAG = SettingsActivity.class.getSimpleName(); 24 | 25 | @Override 26 | protected void onCreate(Bundle savedInstanceState) { 27 | super.onCreate(savedInstanceState); 28 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 29 | 30 | // load settings fragment 31 | getFragmentManager().beginTransaction().replace(android.R.id.content, new MainPreferenceFragment()).commit(); 32 | } 33 | 34 | public static class MainPreferenceFragment extends PreferenceFragment { 35 | @Override 36 | public void onCreate(final Bundle savedInstanceState) { 37 | super.onCreate(savedInstanceState); 38 | addPreferencesFromResource(R.xml.pref_main); 39 | 40 | // gallery EditText change listener 41 | bindPreferenceSummaryToValue(findPreference(getString(R.string.key_print_header))); 42 | bindPreferenceSummaryToValue(findPreference(getString(R.string.key_print_footer))); 43 | 44 | // notification preference change listener 45 | bindPreferenceSummaryToValue(findPreference(getString(R.string.key_print_type))); 46 | bindPreferenceSummaryToValue(findPreference(getString(R.string.key_order_type))); 47 | bindPreferenceSummaryToValue(findPreference(getString(R.string.key_printer_conectivity))); 48 | 49 | // feedback preference click listener 50 | Preference myPref = findPreference(getString(R.string.key_send_feedback)); 51 | myPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { 52 | public boolean onPreferenceClick(Preference preference) { 53 | sendFeedback(getActivity()); 54 | return true; 55 | } 56 | }); 57 | } 58 | } 59 | 60 | @Override 61 | public boolean onOptionsItemSelected(MenuItem item) { 62 | if (item.getItemId() == android.R.id.home) { 63 | onBackPressed(); 64 | 65 | } 66 | return super.onOptionsItemSelected(item); 67 | } 68 | 69 | @Override 70 | public void onBackPressed() { 71 | this.setResult(RESULT_OK); 72 | super.onBackPressed(); 73 | 74 | } 75 | 76 | private static void bindPreferenceSummaryToValue(Preference preference) { 77 | preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener); 78 | 79 | sBindPreferenceSummaryToValueListener.onPreferenceChange(preference, 80 | PreferenceManager 81 | .getDefaultSharedPreferences(preference.getContext()) 82 | .getString(preference.getKey(), "")); 83 | } 84 | 85 | /** 86 | * A preference value change listener that updates the preference's summary 87 | * to reflect its new value. 88 | */ 89 | private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() { 90 | @Override 91 | public boolean onPreferenceChange(Preference preference, Object newValue) { 92 | String stringValue = newValue.toString(); 93 | 94 | if (preference instanceof ListPreference) { 95 | // For list preferences, look up the correct display value in 96 | // the preference's 'entries' list. 97 | ListPreference listPreference = (ListPreference) preference; 98 | int index = listPreference.findIndexOfValue(stringValue); 99 | 100 | // Set the summary to reflect the new value. 101 | preference.setSummary( 102 | index >= 0 103 | ? listPreference.getEntries()[index] 104 | : null); 105 | 106 | } else if (preference instanceof RingtonePreference) { 107 | // For ringtone preferences, look up the correct display value 108 | // using RingtoneManager. 109 | if (TextUtils.isEmpty(stringValue)) { 110 | // Empty values correspond to 'silent' (no ringtone). 111 | preference.setSummary(R.string.pref_ringtone_silent); 112 | 113 | } else { 114 | Ringtone ringtone = RingtoneManager.getRingtone( 115 | preference.getContext(), Uri.parse(stringValue)); 116 | 117 | if (ringtone == null) { 118 | // Clear the summary if there was a lookup error. 119 | preference.setSummary(R.string.summary_choose_ringtone); 120 | } else { 121 | // Set the summary to reflect the new ringtone display 122 | // name. 123 | String name = ringtone.getTitle(preference.getContext()); 124 | preference.setSummary(name); 125 | } 126 | } 127 | 128 | } else if (preference instanceof EditTextPreference) { 129 | if (preference.getKey().equals(R.string.key_print_header)) { 130 | // update the changed gallery name to summary filed 131 | preference.setSummary(stringValue); 132 | } 133 | else if(preference.getKey().equals(R.string.key_print_footer)) { 134 | // update the changed gallery name to summary filed 135 | preference.setSummary(stringValue); 136 | } 137 | } else { 138 | preference.setSummary(stringValue); 139 | } 140 | return true; 141 | } 142 | }; 143 | 144 | /** 145 | * Email client intent to send support mail 146 | * Appends the necessary device information to email body 147 | * useful when providing support 148 | */ 149 | public static void sendFeedback(Context context) { 150 | String body = null; 151 | try { 152 | body = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName; 153 | body = "\n\n-----------------------------\nPlease don't remove this information\n Device OS: Android \n Device OS version: " + 154 | Build.VERSION.RELEASE + "\n App Version: " + body + "\n Device Brand: " + Build.BRAND + 155 | "\n Device Model: " + Build.MODEL + "\n Device Manufacturer: " + Build.MANUFACTURER; 156 | } catch (PackageManager.NameNotFoundException e) { 157 | } 158 | Intent intent = new Intent(Intent.ACTION_SEND); 159 | intent.setType("message/rfc822"); 160 | intent.putExtra(Intent.EXTRA_EMAIL, new String[]{"info@ionob.com"}); 161 | intent.putExtra(Intent.EXTRA_SUBJECT, "Query from android app"); 162 | intent.putExtra(Intent.EXTRA_TEXT, body); 163 | context.startActivity(Intent.createChooser(intent, context.getString(R.string.choose_email_client))); 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /ui/SplashScreenActivity.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.ui 2 | 3 | import android.annotation.SuppressLint 4 | import java.util.Locale 5 | 6 | import android.app.Activity 7 | import android.content.Intent 8 | import android.content.res.Configuration 9 | import android.os.Bundle 10 | import android.os.Handler 11 | import android.util.Log 12 | import android.view.Window 13 | import android.view.WindowManager 14 | import android.widget.Button 15 | 16 | import com.ionob.pos.R 17 | import com.ionob.pos.domain.DateTimeStrategy 18 | import com.ionob.pos.domain.LanguageController 19 | import com.ionob.pos.domain.inventory.Inventory 20 | import com.ionob.pos.domain.sale.Register 21 | import com.ionob.pos.domain.sale.SaleLedger 22 | import com.ionob.pos.db.AndroidDatabase 23 | import com.ionob.pos.db.DatabaseExecutor 24 | import com.ionob.pos.db.inventory.InventoryDaoAndroid 25 | import com.ionob.pos.db.sale.SaleDaoAndroid 26 | import com.ionob.pos.domain.sale.SalesRcord 27 | import com.ionob.pos.ui.sale.ActivityMainMenu 28 | 29 | /** 30 | * This is the first activity page, core-app and database created here. 31 | * Dependency injection happens here. 32 | * 33 | * @author Ionob Team 34 | */ 35 | class SplashScreenActivity : Activity() { 36 | private var goButton: Button? = null 37 | private var gone: Boolean = false 38 | 39 | /** 40 | * Loads database and DAO. 41 | */ 42 | private fun initiateCoreApp() { 43 | val database = AndroidDatabase(this) 44 | val inventoryDao = InventoryDaoAndroid(database) 45 | val saleDao = SaleDaoAndroid(database) 46 | DatabaseExecutor.setDatabase(database) 47 | LanguageController.setDatabase(database) 48 | Inventory.setInventoryDao(inventoryDao) 49 | Register.setSaleDao(saleDao) 50 | SaleLedger.setSaleDao(saleDao) 51 | SalesRcord.setSaleDao(saleDao) 52 | DateTimeStrategy.setLocale("th", "TH") 53 | setLanguage(LanguageController.getInstance().language) 54 | 55 | Log.d("Core App", "INITIATE") 56 | } 57 | 58 | /** 59 | * Set language. 60 | * @param localeString 61 | */ 62 | private fun setLanguage(localeString: String) { 63 | val locale = Locale(localeString) 64 | Locale.setDefault(locale) 65 | val config = Configuration() 66 | config.locale = locale 67 | baseContext.resources.updateConfiguration(config, 68 | baseContext.resources.displayMetrics) 69 | } 70 | 71 | @SuppressLint("MissingSuperCall") 72 | override fun onCreate(savedInstanceState: Bundle?) { 73 | requestWindowFeature(Window.FEATURE_NO_TITLE) 74 | window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, 75 | WindowManager.LayoutParams.FLAG_FULLSCREEN) 76 | initiateUI(savedInstanceState) 77 | initiateCoreApp() 78 | } 79 | 80 | /** 81 | * Go. 82 | */ 83 | private fun go() { 84 | gone = true 85 | val newActivity = Intent(this@SplashScreenActivity, 86 | ActivityMainMenu::class.java) 87 | startActivity(newActivity) 88 | this@SplashScreenActivity.finish() 89 | } 90 | 91 | /** 92 | * Initiate this UI. 93 | * @param savedInstanceState 94 | */ 95 | private fun initiateUI(savedInstanceState: Bundle?) { 96 | super.onCreate(savedInstanceState) 97 | setContentView(R.layout.layout_splashscreen) 98 | // goButton = findViewById(R.id.goButton) as Button 99 | //goButton!!.setOnClickListener { go() } 100 | Handler().postDelayed({ if (!gone) go() }, SPLASH_TIMEOUT) 101 | } 102 | 103 | companion object { 104 | 105 | val POS_VERSION = "Mobile POS 0.8" 106 | private val SPLASH_TIMEOUT: Long = 2000 107 | } 108 | 109 | } -------------------------------------------------------------------------------- /ui/component/ButtonAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.ui.component 2 | 3 | import android.content.Context 4 | import android.view.View 5 | import android.view.ViewGroup 6 | import android.widget.SimpleAdapter 7 | 8 | /** 9 | * An adapter for ListView which able to assign a sub-button in each row data. 10 | * 11 | * @author Ionob Team 12 | */ 13 | class ButtonAdapter 14 | /** 15 | * Construct a new ButtonAdapter 16 | * @param context 17 | * @param data 18 | * @param resource 19 | * @param from 20 | * @param to 21 | * @param buttonId 22 | * @param tag 23 | */ 24 | (context: Context, private val data: List>, 25 | resource: Int, from: Array, to: IntArray, private val buttonId: Int, private val tag: String) : SimpleAdapter(context, data, resource, from, to) { 26 | 27 | override fun getView(position: Int, convertView: View, parent: ViewGroup): View { 28 | val view = super.getView(position, convertView, parent) 29 | (view.findViewById(buttonId) as View).tag = data[position][tag] 30 | return view 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /ui/component/UpdatableFragment.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.ui.component 2 | 3 | import android.support.v4.app.Fragment 4 | import com.ionob.pos.domain.inventory.Product 5 | import com.ionob.pos.ui.inventory.CilckCallBack 6 | 7 | /** 8 | * Fragment which is able to call update() from other class. 9 | * This is used by Delegation pattern. 10 | * 11 | * @author Ionob Team 12 | */ 13 | abstract class UpdatableFragment : Fragment() , CilckCallBack { 14 | 15 | /** 16 | * Update fragment. 17 | */ 18 | abstract fun update() 19 | 20 | override fun onClick(data: Product?) { 21 | 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /ui/inventory/AddProductDialogFragment.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.ui.inventory 2 | 3 | import android.annotation.SuppressLint 4 | import android.content.Intent 5 | import android.content.res.Resources 6 | import android.os.Bundle 7 | import android.support.v4.app.DialogFragment 8 | import android.view.LayoutInflater 9 | import android.view.View 10 | import android.view.ViewGroup 11 | import android.widget.* 12 | 13 | import com.google.zxing.integration.android.IntentIntegrator 14 | import com.google.zxing.integration.android.IntentIntegratorSupportV4 15 | import com.ionob.pos.R 16 | import com.ionob.pos.domain.inventory.Inventory 17 | import com.ionob.pos.domain.inventory.ProductCatalog 18 | import com.ionob.pos.db.NoDaoSetException 19 | import com.ionob.pos.db.Tax.Tax 20 | import com.ionob.pos.db.Tax.TaxDbo 21 | import com.ionob.pos.ui.component.UpdatableFragment 22 | import kotlinx.android.synthetic.main.layout_addproduct.* 23 | import java.math.BigDecimal 24 | import java.util.ArrayList 25 | 26 | /** 27 | * A dialog of adding a Product. 28 | * 29 | * @author Ionob Team 30 | */ 31 | @SuppressLint("ValidFragment") 32 | class AddProductDialogFragment 33 | /** 34 | * Construct a new AddProductDialogFragment 35 | * @param fragment 36 | */ 37 | (private val fragment: UpdatableFragment) : DialogFragment() { 38 | 39 | private var barcodeBox: EditText? = null 40 | private var productCatalog: ProductCatalog? = null 41 | private var scanButton: Button? = null 42 | private var priceBox: EditText? = null 43 | private var nameBox: EditText? = null 44 | private var confirmButton: Button? = null 45 | private var clearButton: Button? = null 46 | private var res: Resources? = null 47 | private var tax_list: ArrayList = ArrayList() 48 | private var unit_price: BigDecimal = BigDecimal.ZERO 49 | private var tax_price: BigDecimal = BigDecimal.ZERO 50 | private var tax_id: Int = 0 51 | private var tax_percent: Double = 0.toDouble() 52 | private var isinclusive_tax_mode: Boolean = true 53 | private var TaxSpinner: Spinner? = null 54 | 55 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 56 | 57 | try { 58 | productCatalog = Inventory.getInstance().getProductCatalog() 59 | } catch (e: NoDaoSetException) { 60 | e.printStackTrace() 61 | } 62 | 63 | val v = inflater!!.inflate(R.layout.layout_addproduct, container, 64 | false) 65 | 66 | res = resources 67 | 68 | barcodeBox = v.findViewById(R.id.barcodeBox) as EditText 69 | scanButton = v.findViewById(R.id.scanButton) as Button 70 | priceBox = v.findViewById(R.id.priceBox) as EditText 71 | nameBox = v.findViewById(R.id.nameBox) as EditText 72 | TaxSpinner = v.findViewById(R.id.taxSpinner) as Spinner 73 | confirmButton = v.findViewById(R.id.confirmButton) as Button 74 | clearButton = v.findViewById(R.id.clearButton) as Button 75 | 76 | initUI() 77 | taxlisting() 78 | return v 79 | } 80 | 81 | /** 82 | * Construct a new 83 | */ 84 | private fun initUI() { 85 | scanButton!!.setOnClickListener { 86 | val scanIntegrator = IntentIntegratorSupportV4(this@AddProductDialogFragment) 87 | scanIntegrator.initiateScan() 88 | } 89 | 90 | confirmButton!!.setOnClickListener { 91 | if (nameBox!!.text.toString() == "" 92 | || barcodeBox!!.text.toString() == "" 93 | || priceBox!!.text.toString() == "") { 94 | 95 | Toast.makeText(activity?.baseContext, 96 | res!!.getString(R.string.please_input_all), Toast.LENGTH_SHORT) 97 | .show() 98 | 99 | } else { 100 | 101 | 102 | unit_price = (priceBox!!.text.toString().toBigDecimal()) 103 | val success = productCatalog!!.addProduct( 104 | nameBox!!.text.toString(), 105 | 55, 106 | barcodeBox!!.text.toString(), 107 | unit_price, 108 | uom!!.text.toString(), 109 | stock?.text?.toString()?.toBigDecimal() ?: BigDecimal.ZERO, 110 | 554, 111 | "image", 112 | tax_id.toInt(), /// on;y need tax id 113 | tax_percent, //uselesss 114 | isinclusive_tax_mode, 115 | tax_price // use less 116 | ) 117 | 118 | if (success) { 119 | Toast.makeText(activity?.baseContext, 120 | res!!.getString(R.string.success) + ", " 121 | + nameBox!!.text.toString(), 122 | Toast.LENGTH_SHORT).show() 123 | 124 | fragment.update() 125 | clearAllBox() 126 | this@AddProductDialogFragment.dismiss() 127 | 128 | } else { 129 | Toast.makeText(activity?.baseContext, 130 | res!!.getString(R.string.fail), 131 | Toast.LENGTH_SHORT).show() 132 | } 133 | } 134 | } 135 | 136 | clearButton!!.setOnClickListener { 137 | if (barcodeBox!!.text.toString() == "" && nameBox!!.text.toString() == "" && priceBox!!.text.toString() == "") { 138 | this@AddProductDialogFragment.dismiss() 139 | } else { 140 | clearAllBox() 141 | } 142 | } 143 | } 144 | 145 | /** 146 | * Clear all box 147 | */ 148 | private fun clearAllBox() { 149 | barcodeBox!!.setText("") 150 | nameBox!!.setText("") 151 | priceBox!!.setText("") 152 | } 153 | 154 | override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) { 155 | val scanningResult = IntentIntegrator.parseActivityResult( 156 | requestCode, resultCode, intent) 157 | 158 | if (scanningResult != null) { 159 | val scanContent = scanningResult.contents 160 | barcodeBox!!.setText(scanContent) 161 | } else { 162 | Toast.makeText(activity?.baseContext, 163 | res!!.getString(R.string.fail), 164 | Toast.LENGTH_SHORT).show() 165 | } 166 | } 167 | 168 | private fun taxlisting() { 169 | 170 | var allTax: List = TaxDbo.getInstance(activity!!.applicationContext).allTax 171 | for (i in 0..allTax.size - 1) { 172 | tax_list.add(allTax[i].tax_name) 173 | 174 | } 175 | 176 | val adapter = ArrayAdapter(activity!!.applicationContext, android.R.layout.simple_expandable_list_item_1, tax_list) 177 | TaxSpinner?.setAdapter(adapter) 178 | 179 | 180 | TaxSpinner?.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { 181 | override fun onNothingSelected(parent: AdapterView<*>?) { 182 | 183 | } 184 | 185 | override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) { 186 | 187 | // val selectedItem = parent!!.getItemAtPosition(position) 188 | val taxposition: Int = parent!!.getItemIdAtPosition(position).toInt() 189 | tax_id = allTax[taxposition].tax_id 190 | tax_percent = allTax[taxposition].tax_percent!!.toDouble() 191 | isinclusive_tax_mode = allTax[taxposition].tax_mode 192 | 193 | 194 | } 195 | 196 | 197 | } 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /ui/inventory/CilckCallBack.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.ui.inventory 2 | 3 | import com.ionob.pos.domain.inventory.Product 4 | import java.math.BigDecimal 5 | 6 | interface CilckCallBack { 7 | 8 | fun onClick(data: Product?) 9 | fun onPlusClicked(data: Product?) 10 | {} 11 | fun onMinuslicked(data: Product?) 12 | {} 13 | fun onQtyEntered(data: Product?,qty:BigDecimal) 14 | {} 15 | 16 | } -------------------------------------------------------------------------------- /ui/inventory/InventeryProductAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.ui.inventory 2 | 3 | import android.annotation.TargetApi 4 | import android.content.Context 5 | import android.content.res.ColorStateList 6 | import android.os.Build 7 | import android.text.Editable 8 | import android.text.TextWatcher 9 | import android.util.Log 10 | import android.view.LayoutInflater 11 | import android.view.View 12 | import android.view.ViewGroup 13 | import android.widget.BaseAdapter 14 | import android.widget.ImageView 15 | import android.widget.TextView 16 | import com.ionob.pos.R 17 | import com.ionob.pos.domain.inventory.Product 18 | import java.math.BigDecimal 19 | 20 | class InventeryProductAdapter (private var cb:CilckCallBack,private var context: Context, private var notesList: MutableList?) : BaseAdapter() { 21 | 22 | private var mlayoutInflater:LayoutInflater?=null 23 | private var productList: MutableList?=null 24 | init { 25 | this.mlayoutInflater= LayoutInflater.from(context) 26 | } 27 | 28 | 29 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 30 | override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View? { 31 | 32 | val view: View? 33 | val vh: ViewHolder 34 | 35 | if (convertView == null) { 36 | view = mlayoutInflater?.inflate(R.layout.item_adapter, parent, false) 37 | vh = ViewHolder(view) 38 | view?.tag = vh 39 | Log.i("JSA", "set Tag for ViewHolder, position: " + position) 40 | } else { 41 | view = convertView 42 | vh = view.tag as ViewHolder 43 | } 44 | vh.id=notesList?.get(position)?.id 45 | vh.name.text = notesList?.get(position)?.name 46 | vh.stockQty.text = notesList?.get(position)?.stockQty.toString() 47 | if( (notesList?.get(position)?.stockQty?:BigDecimal.ZERO).signum()<=0) { 48 | vh.stockQty.setTextColor(context.resources.getColor(R.color.red)) 49 | vh.stockImg.setImageResource((R.drawable.stock_out)) 50 | } 51 | else { 52 | vh.stockQty.setTextColor(context.resources.getColor(R.color.black)) 53 | vh.stockImg.setImageResource((R.drawable.stock_con)) 54 | } 55 | vh.price.text = notesList?.get(position)?.unitPrice.toString() 56 | vh.optView.setOnClickListener { 57 | 58 | cb.onClick(notesList?.get(position)) 59 | } 60 | // view?.setOnClickListener { 61 | // cb.onClick(notesList?.get(position)) 62 | // } 63 | vh.cartPlus.setOnClickListener { 64 | var data=vh.qty.text?.toString()?:"0" 65 | var finalQty=BigDecimal.ZERO 66 | if (data.length>0) 67 | {finalQty=data.toBigDecimal().add(BigDecimal.ONE)} 68 | vh.qty.setText(finalQty.toString()) 69 | cb.onPlusClicked(notesList?.get(position)) 70 | } 71 | 72 | vh.cartMinus.setOnClickListener { 73 | var data=vh.qty.text?.toString()?:"0" 74 | var finalQty=BigDecimal.ZERO 75 | if (data.length>0) 76 | {finalQty=data.toBigDecimal().subtract(BigDecimal.ONE)} 77 | vh.qty.setText(finalQty.toString()) 78 | cb.onPlusClicked(notesList?.get(position)) 79 | } 80 | vh.qty.addTextChangedListener(object : TextWatcher { 81 | override fun afterTextChanged(s: Editable) { 82 | if (s.length > 0) { 83 | cb.onQtyEntered(notesList?.get(position),s.toString().toBigDecimal()) 84 | } 85 | else if(s.length==0) 86 | { 87 | vh.qty.text="0" 88 | } 89 | } 90 | override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {} 91 | override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {} 92 | }) 93 | 94 | return view 95 | } 96 | 97 | override fun getItem(position: Int): Any? { 98 | return notesList!![position] 99 | } 100 | 101 | override fun getItemId(position: Int): Long { 102 | return position.toLong() 103 | } 104 | 105 | override fun getCount(): Int { 106 | return notesList?.size!! 107 | } 108 | } 109 | 110 | private class ViewHolder(view: View?) { 111 | val name: TextView 112 | val qty: TextView 113 | val stockQty: TextView 114 | val stockImg: ImageView 115 | val price: TextView 116 | val cartPlus: ImageView 117 | val cartMinus: ImageView 118 | var id:Int?=0 119 | val optView:View 120 | 121 | init { 122 | this.name = view?.findViewById(R.id.from_name) as TextView 123 | this.qty = view?.findViewById(R.id.cart_product_quantity_tv) as TextView 124 | this.stockQty = view?.findViewById(R.id.plist_stock_text) as TextView 125 | this.price = view?.findViewById(R.id.plist_price_text) as TextView 126 | this.optView=view?.findViewById(R.id.optionView) 127 | this.cartPlus=view?.findViewById(R.id.cart_plus_img) 128 | this.cartMinus=view?.findViewById(R.id.cart_minus_img) 129 | this.stockImg=view?.findViewById(R.id.stock_img) 130 | } 131 | 132 | // if you target API 26, you should change to: 133 | // init { 134 | // this.tvTitle = view?.findViewById(R.id.tvTitle) as TextView 135 | // this.tvContent = view?.findViewById(R.id.tvContent) as TextView 136 | // } 137 | } -------------------------------------------------------------------------------- /ui/sale/ActivityMainMenu.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.ui.sale 2 | 3 | 4 | import android.content.Intent 5 | import com.ionob.pos.R 6 | 7 | 8 | /** 9 | * This is the first activity page, core-app and database created here. 10 | * Dependency injection happens here. 11 | * 12 | * @author Ionob Team 13 | */ 14 | import android.content.res.ColorStateList 15 | import android.os.Build 16 | import android.os.Bundle 17 | import android.support.design.widget.CollapsingToolbarLayout 18 | import android.support.design.widget.FloatingActionButton 19 | import android.support.v4.view.ViewCompat 20 | import android.support.v7.app.AppCompatActivity 21 | import android.support.v7.graphics.Palette 22 | import android.support.v7.widget.CardView 23 | import android.support.v7.widget.Toolbar 24 | import android.transition.Slide 25 | import android.view.* 26 | import android.widget.GridView 27 | import android.widget.ImageView 28 | import com.fitbae.fitness.dialogs.FBCustomerDialog 29 | import com.ionob.pos.db.customer.CustomerDbao 30 | import com.ionob.pos.settings.MainSettingsActivity 31 | import com.ionob.pos.ui.sale.model.CustomerModel 32 | import com.ionob.pos.utils.IONPreferences 33 | import java.util.ArrayList 34 | 35 | 36 | class ActivityMainMenu : AppCompatActivity() ,View.OnClickListener { 37 | 38 | 39 | private var collapsingToolbarLayout: CollapsingToolbarLayout? = null 40 | private var salseBuuton:CardView?=null 41 | 42 | override fun onCreate(savedInstanceState: Bundle?) { 43 | super.onCreate(savedInstanceState) 44 | initActivityTransitions() 45 | setContentView(R.layout.activity_main) 46 | ViewCompat.setTransitionName(findViewById(R.id.app_bar_layout), EXTRA_IMAGE) 47 | supportPostponeEnterTransition() 48 | setSupportActionBar(findViewById(R.id.toolbar) as Toolbar) 49 | supportActionBar!!.setDisplayHomeAsUpEnabled(true) 50 | val itemTitle = intent.getStringExtra(EXTRA_TITLE) 51 | collapsingToolbarLayout = findViewById(R.id.collapsing_toolbar) as CollapsingToolbarLayout 52 | collapsingToolbarLayout!!.title = itemTitle 53 | collapsingToolbarLayout!!.setExpandedTitleColor(resources.getColor(android.R.color.transparent)) 54 | 55 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 56 | var window = getWindow(); 57 | window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); 58 | window.setStatusBarColor(resources.getColor(R.color.primary)); 59 | } 60 | val image = findViewById(R.id.image) as ImageView 61 | // Picasso.with(this).load(intent.getStringExtra(EXTRA_IMAGE)).into(image, object : Callback() { 62 | // fun onSuccess() { 63 | // val bitmap = (image.drawable as BitmapDrawable).bitmap 64 | // Palette.from(bitmap).generate { palette -> applyPalette(palette) } 65 | // } 66 | // 67 | // fun onError() { 68 | // 69 | // } 70 | // }) 71 | 72 | // val title = findViewById(R.id.title) as TextView 73 | // title.text = itemTitle 74 | 75 | setListeners() 76 | } 77 | 78 | fun setListeners() 79 | { 80 | salseBuuton=findViewById(R.id.sales_card) as CardView 81 | salseBuuton?.setOnClickListener(this) 82 | 83 | } 84 | 85 | override fun dispatchTouchEvent(motionEvent: MotionEvent): Boolean { 86 | try { 87 | return super.dispatchTouchEvent(motionEvent) 88 | } catch (e: NullPointerException) { 89 | return false 90 | } 91 | 92 | } 93 | 94 | override fun onEnterAnimationComplete() { 95 | super.onEnterAnimationComplete() 96 | // (findViewById(R.id.mainGrid)as android.support.v7.widget.GridLayout)!!.scheduleLayoutAnimation() 97 | } 98 | 99 | override fun onCreateOptionsMenu(menu: Menu): Boolean { 100 | val inflater = menuInflater 101 | inflater.inflate(R.menu.main_menu, menu) 102 | return true 103 | } 104 | 105 | 106 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 107 | when (item.itemId) { 108 | R.id.choose_customer -> { 109 | var customerDb= CustomerDbao.getInstance(applicationContext) 110 | var data=customerDb.allCustomer 111 | var customerSearchDlg= FBCustomerDialog() 112 | customerSearchDlg.setCallback(object : FBCustomerDialog.SelectCstomerCallback{ 113 | override fun onSelectCustomer(customr: CustomerModel) { 114 | IONPreferences.setSelectedCustomerId(customr?.customerId) 115 | 116 | } 117 | 118 | override fun onSelectedNoCustomer() { 119 | 120 | 121 | } 122 | }) 123 | var bundle=Bundle() 124 | bundle.putSerializable("COSTOMER_LIST",data as ArrayList) 125 | customerSearchDlg.arguments=bundle 126 | customerSearchDlg?.show(supportFragmentManager,"customer_search-dialog") 127 | } 128 | R.id.settings -> { 129 | 130 | startActivity(Intent(this@ActivityMainMenu, MainSettingsActivity::class.java)) 131 | } 132 | 133 | else -> return super.onOptionsItemSelected(item) 134 | } 135 | return false 136 | } 137 | 138 | private fun initActivityTransitions() { 139 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 140 | val transition = Slide() 141 | transition.excludeTarget(android.R.id.statusBarBackground, true) 142 | window.enterTransition = transition 143 | window.returnTransition = transition 144 | } 145 | } 146 | 147 | private fun applyPalette(palette: Palette) { 148 | val primaryDark = resources.getColor(R.color.ColorPrimary) 149 | val primary = resources.getColor(R.color.primary) 150 | collapsingToolbarLayout!!.setContentScrimColor(palette.getMutedColor(primary)) 151 | collapsingToolbarLayout!!.setStatusBarScrimColor(palette.getDarkMutedColor(primaryDark)) 152 | updateBackground(findViewById(R.id.fab) as FloatingActionButton, palette) 153 | supportStartPostponedEnterTransition() 154 | } 155 | 156 | private fun updateBackground(fab: FloatingActionButton, palette: Palette) { 157 | val lightVibrantColor = palette.getLightVibrantColor(resources.getColor(android.R.color.white)) 158 | val vibrantColor = palette.getVibrantColor(resources.getColor(R.color.accent_material_dark)) 159 | 160 | fab.rippleColor = lightVibrantColor 161 | fab.backgroundTintList = ColorStateList.valueOf(vibrantColor) 162 | } 163 | 164 | companion object { 165 | 166 | private val EXTRA_IMAGE = "com.antonioleiva.materializeyourapp.extraImage" 167 | private val EXTRA_TITLE = "com.antonioleiva.materializeyourapp.extraTitle" 168 | 169 | // fun navigate(activity: AppCompatActivity, transitionImage: View) { 170 | // val intent = Intent(activity, DetailActivity::class.java) 171 | // intent.putExtra(EXTRA_IMAGE, viewModel.getImage()) 172 | // intent.putExtra(EXTRA_TITLE, viewModel.getText()) 173 | // 174 | // val options = ActivityOptionsCompat.makeSceneTransitionAnimation(activity, transitionImage, EXTRA_IMAGE) 175 | // ActivityCompat.startActivity(activity, intent, options.toBundle()) 176 | // } 177 | } 178 | 179 | override fun onClick(view: View?) { 180 | 181 | when(view?.id!!) 182 | { 183 | R.id.sales_card-> 184 | { 185 | startActivity(Intent(this,ActivitySalesRecord::class.java)) 186 | } 187 | 188 | 189 | } 190 | } 191 | 192 | } 193 | -------------------------------------------------------------------------------- /ui/sale/EditFragmentDialog.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.ui.sale 2 | 3 | import android.annotation.SuppressLint 4 | import android.graphics.Color 5 | import android.graphics.drawable.ColorDrawable 6 | import android.os.Bundle 7 | import android.preference.PreferenceManager 8 | import android.support.v4.app.DialogFragment 9 | import android.util.Log 10 | import android.view.LayoutInflater 11 | import android.view.View 12 | import android.view.ViewGroup 13 | import android.widget.Button 14 | import android.widget.EditText 15 | import android.widget.ImageView 16 | import android.widget.TextView 17 | 18 | import com.ionob.pos.R 19 | import com.ionob.pos.domain.inventory.LineItem 20 | import com.ionob.pos.domain.sale.Register 21 | import com.ionob.pos.db.NoDaoSetException 22 | import com.ionob.pos.domain.inventory.Inventory 23 | import com.ionob.pos.domain.inventory.ProductCatalog 24 | import com.ionob.pos.ui.component.UpdatableFragment 25 | import kotlinx.android.synthetic.main.dialog_saleedit.* 26 | import java.math.BigDecimal 27 | 28 | /** 29 | * A dialog for edit a LineItem of sale, 30 | * overriding price or set the quantity. 31 | * @author Ionob Team 32 | */ 33 | @SuppressLint("ValidFragment") 34 | class EditFragmentDialog 35 | /** 36 | * Construct a new EditFragmentDialog. 37 | * @param saleFragment 38 | * @param reportFragment 39 | */ 40 | (private val saleFragment: UpdatableFragment, private val reportFragment: UpdatableFragment) : DialogFragment() , View.OnClickListener{ 41 | 42 | 43 | private var register: Register? = null 44 | private var quantityBox: EditText? = null 45 | private var priceBox: EditText? = null 46 | private var comfirmButton: Button? = null 47 | private var saleId: String? = null 48 | private var position: String? = null 49 | private var lineItem: LineItem? = null 50 | private var removeButton: Button? = null 51 | private var isNew:Boolean=false 52 | private var productId:Int = 0 53 | private var produName:TextView?= null 54 | private var outofStockText:TextView?= null 55 | var productCatalog: ProductCatalog? = null 56 | private var plusButton: ImageView? = null 57 | private var minusButton: ImageView? = null 58 | private var discountImAmt:EditText?=null 59 | private var discountPerccent:EditText?=null 60 | private var netAmount:BigDecimal= BigDecimal.ZERO 61 | private var stockQty:BigDecimal= BigDecimal.ZERO 62 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 63 | return inflater!!.inflate(R.layout.dialog_saleedit, container, false) 64 | } 65 | 66 | override fun onViewCreated(v: View, savedInstanceState: Bundle?) { 67 | 68 | try { 69 | register = Register.getInstance() 70 | } catch (e: NoDaoSetException) { 71 | e.printStackTrace() 72 | } 73 | dialog.window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) 74 | quantityBox = v.findViewById(R.id.quantityBox) as EditText 75 | priceBox = v.findViewById(R.id.priceBox) as EditText 76 | comfirmButton = v.findViewById(R.id.confirmButton) as Button 77 | removeButton = v.findViewById(R.id.removeButton) as Button 78 | produName=v.findViewById(R.id.product_name) as TextView 79 | outofStockText=v.findViewById(R.id.out_of_stock_text) as TextView 80 | plusButton=v.findViewById(R.id.plus_btn) as ImageView 81 | minusButton=v.findViewById(R.id.minus_icon) as ImageView 82 | 83 | plusButton?.setOnClickListener(this) 84 | minusButton?.setOnClickListener(this) 85 | saleId = arguments?.getString("sale_id") 86 | position = arguments?.getString("position") 87 | if (arguments!!.containsKey("isNewItem") && arguments!!.containsKey("product_id")) { 88 | try { 89 | productCatalog = Inventory.getInstance().getProductCatalog() 90 | } catch (e: NoDaoSetException) { 91 | e.printStackTrace() 92 | } 93 | 94 | isNew = arguments!!.getBoolean("isNewItem") 95 | productId = arguments!!.getInt("product_id") 96 | removeButton?.visibility=View.GONE 97 | var line=register?.getSalesLine(saleId?.toInt()?:0,productId) 98 | quantityBox!!.setText((line?.quantity?:0).toString()) 99 | priceBox?.setText(productCatalog?.getProductById(productId)?.unitPrice.toString() ) 100 | produName?.setText(productCatalog?.getProductById(productId)?.name) 101 | stockQty=productCatalog?.getProductById(productId)?.stockQty?: BigDecimal.ZERO 102 | stock_qty.setText(stockQty.toString()) 103 | uom.setText(productCatalog?.getProductById(productId)?.uom) 104 | 105 | 106 | } else { 107 | removeButton?.visibility=View.VISIBLE 108 | lineItem = register?.getCurrentSale()!!.getLineItemAt(Integer.parseInt(position)) 109 | stockQty=lineItem?.product?.stockQty?: BigDecimal.ZERO 110 | quantityBox?.setText(lineItem?.quantity.toString()) 111 | priceBox?.setText(lineItem?.product!!.unitPrice.toString() ) 112 | produName?.setText(lineItem?.product!!.name) 113 | } 114 | removeButton!!.setOnClickListener { 115 | Log.d("remove", "id=" + lineItem!!.id) 116 | register!!.removeItem(lineItem!!) 117 | dismissDialog() 118 | } 119 | 120 | comfirmButton!!.setOnClickListener { 121 | 122 | var isStockCheckenabled=PreferenceManager.getDefaultSharedPreferences(activity).getBoolean(getString(R.string.key_check_stock),true) 123 | if(quantityBox?.text?.equals("0")==true) return@setOnClickListener 124 | if(isStockCheckenabled) 125 | validateStockandInsert() 126 | else { 127 | addOrupdateLine() 128 | dismissDialog() 129 | } 130 | } 131 | 132 | } 133 | 134 | private fun validateStockandInsert() { 135 | if ((quantityBox!!.text?.toString()?.toBigDecimal() 136 | ?: BigDecimal.ZERO).compareTo(stockQty) <= 0) { 137 | outofStockText?.visibility = View.GONE 138 | addOrupdateLine() 139 | dismissDialog() 140 | } else { 141 | outofStockText?.visibility = View.VISIBLE 142 | } 143 | } 144 | 145 | private fun addOrupdateLine() { 146 | if (isNew) { 147 | register?.addItem(productCatalog?.getProductById(productId), quantityBox!!.text.toString().toBigDecimal()) 148 | 149 | } else { 150 | register!!.updateItem( 151 | Integer.parseInt(saleId), 152 | lineItem!!, 153 | (quantityBox!!.text.toString().toBigDecimal()), 154 | (priceBox!!.text.toString().toBigDecimal()) 155 | ) 156 | } 157 | 158 | } 159 | 160 | override fun onClick(p0: View) { 161 | 162 | when(p0.id) 163 | { 164 | R.id.plus_btn->{ 165 | var qty=quantityBox?.text 166 | if(qty.isNullOrEmpty()) { 167 | quantityBox?.setText("0") 168 | } 169 | quantityBox?.setText(quantityBox?.text.toString()?.toBigDecimal().add(BigDecimal.ONE).toString()) } 170 | R.id.minus_icon->{ 171 | var qty=quantityBox?.text 172 | if(qty.isNullOrEmpty()) { 173 | quantityBox?.setText("0") 174 | } 175 | if((quantityBox?.text?.toString().equals("0"))) 176 | return 177 | quantityBox?.setText(quantityBox?.text.toString()?.toBigDecimal().subtract(BigDecimal.ONE).toString()) 178 | } 179 | } 180 | 181 | } 182 | 183 | /** 184 | * End. 185 | */ 186 | private fun dismissDialog() { 187 | saleFragment.update() 188 | // reportFragment.update() 189 | this.dismiss() 190 | } 191 | 192 | 193 | } 194 | -------------------------------------------------------------------------------- /ui/sale/EndPaymentFragmentDialog.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.ui.sale 2 | 3 | import android.annotation.SuppressLint 4 | import android.os.Bundle 5 | import android.support.v4.app.DialogFragment 6 | import android.view.LayoutInflater 7 | import android.view.View 8 | import android.view.ViewGroup 9 | import android.widget.Button 10 | import android.widget.TextView 11 | 12 | import com.ionob.pos.R 13 | import com.ionob.pos.domain.DateTimeStrategy 14 | import com.ionob.pos.domain.sale.Register 15 | import com.ionob.pos.db.NoDaoSetException 16 | import com.ionob.pos.ui.component.UpdatableFragment 17 | 18 | /** 19 | * A dialog shows the total change and confirmation for Sale. 20 | * @author Ionob Team 21 | */ 22 | @SuppressLint("ValidFragment") 23 | class EndPaymentFragmentDialog 24 | /** 25 | * End this UI. 26 | * @param saleFragment 27 | * @param reportFragment 28 | */ 29 | (private val saleFragment: UpdatableFragment, private val reportFragment: UpdatableFragment) : DialogFragment() { 30 | 31 | private var doneButton: Button? = null 32 | private var chg: TextView? = null 33 | private var regis: Register? = null 34 | 35 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 36 | try { 37 | regis = Register.getInstance() 38 | } catch (e: NoDaoSetException) { 39 | e.printStackTrace() 40 | } 41 | 42 | val v = inflater!!.inflate(R.layout.dialog_paymentsuccession, container, false) 43 | val strtext = arguments!!.getString("edttext") 44 | chg = v.findViewById(R.id.changeTxt) as TextView 45 | chg!!.text = strtext 46 | doneButton = v.findViewById(R.id.doneButton) as Button 47 | doneButton!!.setOnClickListener { end() } 48 | 49 | return v 50 | } 51 | 52 | /** 53 | * End 54 | */ 55 | private fun end() { 56 | regis!!.endSale(DateTimeStrategy.currentTime) 57 | saleFragment.update() 58 | reportFragment.update() 59 | this.dismiss() 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /ui/sale/PaymentFragment.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.ui.sale 2 | 3 | import android.app.AlertDialog 4 | 5 | import android.content.Intent 6 | import android.os.Bundle 7 | import android.text.Editable 8 | import android.text.TextWatcher 9 | import android.view.LayoutInflater 10 | import android.view.View 11 | import android.view.ViewGroup 12 | import android.widget.* 13 | 14 | import com.ionob.pos.R 15 | import com.ionob.pos.domain.DateTimeStrategy 16 | import com.ionob.pos.domain.sale.Sale 17 | import com.ionob.pos.domain.sale.Register 18 | import com.ionob.pos.ui.MainActivity 19 | import com.ionob.pos.ui.component.UpdatableFragment 20 | import kotlinx.android.synthetic.main.layout_payment.* 21 | import suman.com.andoirdbluetoothprint.MainActivityPrint 22 | import java.math.BigDecimal 23 | import java.math.RoundingMode 24 | import java.text.DecimalFormat 25 | 26 | /** 27 | * UI for showing payment 28 | * @author Ionob Team 29 | */ 30 | class PaymentFragment : UpdatableFragment() { 31 | 32 | 33 | 34 | var register:Register?=null 35 | var isViewCreated=false 36 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 37 | val view = inflater!!.inflate(R.layout.layout_payment, container, false) 38 | return view 39 | } 40 | 41 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 42 | super.onViewCreated(view, savedInstanceState) 43 | register= Register.getInstance() 44 | isViewCreated=true 45 | confirmButton.setOnClickListener { 46 | var sale=register?.getCurrentSale() 47 | writ_off_amount?.text?.toString()?.let { if (!it.isNullOrEmpty()) sale?.discountAmountt=it.toBigDecimal()} 48 | sale?.referenceNumber=reference_no?.text?.toString() 49 | sale?.subTotal?.let { 50 | if(slectedPaymentMode!= CREDIT) 51 | sale?.amountPaid = it 52 | else 53 | sale?.amountPaid = BigDecimal.ZERO 54 | // sale?.subTotal = it 55 | } 56 | // else 57 | // { 58 | // showCreditConfirmClearDialog(sale) 59 | // // Toast.makeText(,Toast.LENGTH_LONG).show() 60 | // return@setOnClickListener 61 | // 62 | // }} 63 | sale?.paymentType=slectedPaymentMode 64 | register?.endSale(DateTimeStrategy.currentTime) 65 | startActivity(Intent(activity 66 | ,MainActivityPrint::class.java)) 67 | } 68 | manageDicuountSheet() 69 | initRadioButtons() 70 | } 71 | private fun showCreditConfirmClearDialog(sale: Sale?) { 72 | val dialog = AlertDialog.Builder(activity) 73 | dialog.setTitle("Warning") 74 | dialog.setMessage("No payment amount!! Sales will Save as CREDIT ?") 75 | dialog.setPositiveButton(activity?.getString(R.string.no)) { dialog, which -> } 76 | dialog.setNegativeButton(activity?.getString(R.string.okay)) { dialog, which -> 77 | slectedPaymentMode= CREDIT 78 | sale?.paymentType=slectedPaymentMode 79 | register?.endSale(DateTimeStrategy.currentTime) 80 | startActivity(Intent(activity 81 | ,MainActivityPrint::class.java)) 82 | dialog.dismiss() 83 | } 84 | 85 | dialog.show() 86 | } 87 | override fun setUserVisibleHint(isVisibleToUser: Boolean) { 88 | super.setUserVisibleHint(isVisibleToUser) 89 | if(isVisibleToUser&&isViewCreated) { 90 | update() 91 | (activity as MainActivity)?.hideView() 92 | } 93 | } 94 | 95 | 96 | override fun update() { 97 | if (register!!.hasSale()) { 98 | writ_off_amount?.setText("") 99 | writ_off_percent?.setText("") 100 | 101 | gross_amount?.text =register?.total!!.subtract(register?.totaltax).toFormatedString() 102 | taxt_total?.text = register!!.totaltax.toFormatedString() + "" 103 | line_discount_total?.text=register?.totalDiscount?.toFormatedString() 104 | net_amount?.setText(register?.total?.subtract(register?.totalDiscount)?.toFormatedString()) 105 | line_net_total?.text=register?.total?.subtract(register?.totalDiscount)?.toFormatedString() 106 | this.netAmount=register?.total?.subtract(register?.totalDiscount) 107 | register?.getCurrentSale()?.subTotal=netAmount 108 | 109 | } else { 110 | 111 | gross_amount?.text ="00.00" 112 | line_discount_total?.text="00.00" 113 | taxt_total?.text="00.00" 114 | this.netAmount= BigDecimal.ZERO 115 | } 116 | 117 | } 118 | 119 | var netAmount=BigDecimal.ZERO 120 | 121 | 122 | 123 | override fun onResume() { 124 | super.onResume() 125 | update(); 126 | // it shouldn't call update() anymore. Because super.onResume() 127 | // already fired the action of spinner.onItemSelected() 128 | } 129 | 130 | 131 | 132 | fun manageDicuountSheet() 133 | { 134 | var discountAmt=BigDecimal.ZERO 135 | var tempNet=BigDecimal.ZERO 136 | writ_off_amount.addTextChangedListener(object : TextWatcher { 137 | override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { 138 | 139 | } 140 | 141 | override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { 142 | 143 | } 144 | 145 | override fun afterTextChanged(s: Editable) { 146 | if ( writ_off_amount.hasFocus()) { 147 | try{ 148 | if (s.length >=0) { 149 | try { 150 | discountAmt = BigDecimal(s.toString()).setScale(2, RoundingMode.HALF_UP) 151 | } catch (e: Exception) { 152 | discountAmt = BigDecimal.ZERO 153 | } 154 | tempNet= netAmount.subtract(discountAmt) 155 | 156 | } 157 | if (tempNet.signum()!! < 0) { 158 | discountAmt = netAmount 159 | tempNet = BigDecimal.ZERO 160 | writ_off_amount.setText(discountAmt.toFormatedString()) 161 | } 162 | if (netAmount.signum()==0){ return} 163 | var discPercent = discountAmt.divide(netAmount,2, RoundingMode.HALF_UP) 164 | discPercent = discPercent.scaleByPowerOfTen(2) 165 | writ_off_percent.setText(discPercent.toFormatedString()) 166 | register?.getCurrentSale()?.subTotal=tempNet 167 | net_amount.setText(tempNet.toFormatedString()) 168 | } 169 | catch (e:NumberFormatException){e.printStackTrace()} 170 | } 171 | 172 | } 173 | }) 174 | 175 | writ_off_percent.addTextChangedListener(object : TextWatcher { 176 | override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { 177 | 178 | } 179 | 180 | override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { 181 | 182 | } 183 | 184 | override fun afterTextChanged(s: Editable) { 185 | if (writ_off_percent.hasFocus()) { 186 | 187 | try { 188 | if (s.length >= 0) { 189 | var percent = if (s.toString().isNullOrEmpty()) BigDecimal.ZERO else s.toString()?.toBigDecimal() 190 | discountAmt = (percent.setScale(2, RoundingMode.HALF_UP).multiply(netAmount).scaleByPowerOfTen(-2)) 191 | tempNet = netAmount.subtract(discountAmt) 192 | } 193 | if (tempNet.signum()!! < 0) { 194 | discountAmt = netAmount 195 | tempNet = BigDecimal.ZERO 196 | writ_off_amount.setText(discountAmt.toFormatedString()) 197 | writ_off_percent.setText("100") 198 | } 199 | writ_off_amount.setText((discountAmt).toFormatedString()) 200 | register?.getCurrentSale()?.subTotal = tempNet 201 | net_amount.setText(tempNet.toFormatedString()) 202 | } 203 | catch (e:NumberFormatException){e.printStackTrace()} 204 | } 205 | 206 | } 207 | }) 208 | 209 | 210 | 211 | 212 | } 213 | 214 | var slectedPaymentMode= CASH 215 | private fun initRadioButtons() { 216 | radio_cash.isChecked=true 217 | payment_type_group.setOnCheckedChangeListener(RadioGroup.OnCheckedChangeListener { group, checkedId -> 218 | 219 | when (checkedId) { 220 | R.id.radio_cash -> { 221 | 222 | slectedPaymentMode= CASH 223 | } 224 | R.id.radio_credit -> { 225 | 226 | slectedPaymentMode= CREDIT 227 | 228 | } 229 | R.id.radio_card -> { 230 | slectedPaymentMode= CARD 231 | } 232 | R.id.radio_cheque -> { 233 | slectedPaymentMode= CHECK 234 | } 235 | R.id.radio_netbanking -> { 236 | slectedPaymentMode= NET 237 | } 238 | R.id.radio_upi-> { 239 | slectedPaymentMode= UPI 240 | } 241 | 242 | } 243 | 244 | }) 245 | } 246 | 247 | companion object { 248 | val CREDIT = "credit" 249 | val CASH = "cash" 250 | val CARD = "card" 251 | val CHECK = "check" 252 | val NET = "net" 253 | val UPI="upi" 254 | } 255 | 256 | 257 | } 258 | 259 | fun BigDecimal.toFormatedString(): String { 260 | 261 | val df = DecimalFormat("#,###.00") 262 | return df.format(this) 263 | } 264 | fun String.toFormatedString(): String { 265 | 266 | val df = DecimalFormat("#,###.00") 267 | return df.format(this) 268 | } -------------------------------------------------------------------------------- /ui/sale/PaymentFragmentDialog.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.ui.sale 2 | 3 | import com.ionob.pos.R 4 | import com.ionob.pos.ui.component.UpdatableFragment 5 | 6 | import android.annotation.SuppressLint 7 | import android.os.Bundle 8 | import android.support.v4.app.DialogFragment 9 | import android.view.LayoutInflater 10 | import android.view.View 11 | import android.view.ViewGroup 12 | import android.widget.Button 13 | import android.widget.EditText 14 | import android.widget.TextView 15 | import android.widget.Toast 16 | 17 | /** 18 | * A dialog for input a money for sale. 19 | * @author Ionob Team 20 | */ 21 | @SuppressLint("ValidFragment") 22 | class PaymentFragmentDialog 23 | /** 24 | * Construct a new PaymentFragmentDialog. 25 | * @param saleFragment 26 | * @param reportFragment 27 | */ 28 | (private val saleFragment: UpdatableFragment, private val reportFragment: UpdatableFragment) : DialogFragment() { 29 | 30 | private var totalPrice: TextView? = null 31 | private var input: EditText? = null 32 | private var clearButton: Button? = null 33 | private var confirmButton: Button? = null 34 | private var strtext: String? = null 35 | 36 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 37 | val v = inflater!!.inflate(R.layout.dialog_payment, container, false) 38 | strtext = arguments?.getString("edttext") 39 | input = v.findViewById(R.id.dialog_saleInput) as EditText 40 | totalPrice = v.findViewById(R.id.payment_total) as TextView 41 | totalPrice!!.text = strtext 42 | clearButton = v.findViewById(R.id.clearButton) as Button 43 | clearButton!!.setOnClickListener { end() } 44 | 45 | confirmButton = v.findViewById(R.id.confirmButton) as Button 46 | confirmButton!!.setOnClickListener(View.OnClickListener { 47 | val inputString = input!!.text.toString() 48 | 49 | if (inputString == "") { 50 | Toast.makeText(activity?.baseContext, resources.getString(R.string.please_input_all), Toast.LENGTH_SHORT).show() 51 | return@OnClickListener 52 | } 53 | val a = java.lang.Double.parseDouble(strtext) 54 | val b = java.lang.Double.parseDouble(inputString) 55 | if (b < a) { 56 | Toast.makeText(activity?.baseContext, resources.getString(R.string.need_money) + " " + (b - a), Toast.LENGTH_SHORT).show() 57 | } else { 58 | val bundle = Bundle() 59 | bundle.putString("edttext", (b - a).toString() + "") 60 | val newFragment = EndPaymentFragmentDialog( 61 | saleFragment, reportFragment) 62 | newFragment.arguments = bundle 63 | newFragment.show(fragmentManager, "") 64 | end() 65 | } 66 | }) 67 | return v 68 | } 69 | 70 | /** 71 | * End. 72 | */ 73 | private fun end() { 74 | this.dismiss() 75 | 76 | } 77 | 78 | 79 | } 80 | -------------------------------------------------------------------------------- /ui/sale/ReportFragment.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.ui.sale 2 | 3 | import java.util.Calendar 4 | 5 | import android.app.DatePickerDialog 6 | import android.content.Intent 7 | import android.os.Bundle 8 | import android.view.LayoutInflater 9 | import android.view.View 10 | import android.view.ViewGroup 11 | import android.widget.AdapterView 12 | import android.widget.AdapterView.OnItemClickListener 13 | import android.widget.AdapterView.OnItemSelectedListener 14 | import android.widget.ArrayAdapter 15 | import android.widget.Button 16 | import android.widget.ListView 17 | import android.widget.SimpleAdapter 18 | import android.widget.Spinner 19 | import android.widget.TextView 20 | 21 | import com.ionob.pos.R 22 | import com.ionob.pos.domain.DateTimeStrategy 23 | import com.ionob.pos.domain.sale.Sale 24 | import com.ionob.pos.domain.sale.SaleLedger 25 | import com.ionob.pos.db.NoDaoSetException 26 | import com.ionob.pos.ui.component.UpdatableFragment 27 | import java.math.BigDecimal 28 | import kotlin.collections.ArrayList 29 | 30 | /** 31 | * UI for showing sale's record. 32 | * @author Ionob Team 33 | */ 34 | class ReportFragment : UpdatableFragment() { 35 | 36 | 37 | private var saleLedger: SaleLedger? = null 38 | internal var saleList: MutableList>? = null 39 | private var saleLedgerListView: ListView? = null 40 | private var totalBox: TextView? = null 41 | private var spinner: Spinner? = null 42 | private var previousButton: Button? = null 43 | private var nextButton: Button? = null 44 | private var currentBox: TextView? = null 45 | private var currentTime: Calendar? = null 46 | private var datePicker: DatePickerDialog? = null 47 | 48 | 49 | 50 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 51 | 52 | try { 53 | saleLedger = SaleLedger.getInstance() 54 | } catch (e: NoDaoSetException) { 55 | e.printStackTrace() 56 | } 57 | 58 | val view = inflater!!.inflate(R.layout.layout_report, container, false) 59 | 60 | previousButton = view.findViewById(R.id.previousButton) as Button 61 | nextButton = view.findViewById(R.id.nextButton) as Button 62 | currentBox = view.findViewById(R.id.currentBox) as TextView 63 | saleLedgerListView = view.findViewById(R.id.saleListView) as ListView 64 | totalBox = view.findViewById(R.id.totalBox) as TextView 65 | spinner = view.findViewById(R.id.spinner1) as Spinner 66 | 67 | initUI() 68 | return view 69 | } 70 | 71 | /** 72 | * Initiate this UI. 73 | */ 74 | private fun initUI() { 75 | currentTime = Calendar.getInstance() 76 | datePicker = DatePickerDialog(activity, DatePickerDialog.OnDateSetListener { view, y, m, d -> 77 | currentTime!!.set(Calendar.YEAR, y) 78 | currentTime!!.set(Calendar.MONTH, m) 79 | currentTime!!.set(Calendar.DAY_OF_MONTH, d) 80 | update() 81 | }, currentTime!!.get(Calendar.YEAR), currentTime!!.get(Calendar.MONTH), currentTime!!.get(Calendar.DAY_OF_MONTH)) 82 | 83 | val adapter = ArrayAdapter.createFromResource(activity?.baseContext, 84 | R.array.period, android.R.layout.simple_spinner_item) 85 | adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) 86 | 87 | // spinner!!.adapter = adapter 88 | /* spinner!!.setSelection(0) 89 | spinner!!.onItemSelectedListener = object : OnItemSelectedListener { 90 | 91 | override fun onItemSelected(parent: AdapterView<*>, view: View, pos: Int, id: Long) { 92 | update() 93 | } 94 | 95 | override fun onNothingSelected(parent: AdapterView<*>) {} 96 | 97 | }*/ 98 | 99 | currentBox!!.setOnClickListener { datePicker!!.show() } 100 | 101 | 102 | 103 | previousButton!!.setOnClickListener { addDate(-1) } 104 | 105 | nextButton!!.setOnClickListener { addDate(1) } 106 | 107 | saleLedgerListView!!.onItemClickListener = OnItemClickListener { myAdapter, myView, position, mylng -> 108 | val id = saleList?.get(position)?.get("id")?.toString() 109 | val newActivity = Intent(activity?.baseContext, SaleDetailActivity::class.java) 110 | newActivity.putExtra("id", id) 111 | startActivity(newActivity) 112 | } 113 | 114 | } 115 | 116 | /** 117 | * Show list. 118 | * @param list 119 | */ 120 | private fun showList(list: List) { 121 | 122 | saleList = ArrayList() 123 | for (sale in list) { 124 | // (saleList as ArrayList>).add(sale.toMap()) 125 | } 126 | 127 | val sAdap = SimpleAdapter(activity?.baseContext, saleList, 128 | R.layout.listview_report, arrayOf("id", "startTime", "total"), 129 | intArrayOf(R.id.sid, R.id.startTime, R.id.total)) 130 | saleLedgerListView!!.adapter = sAdap 131 | } 132 | 133 | override fun update() { 134 | val period = spinner!!.selectedItemPosition 135 | var list: List? = null 136 | val cTime = currentTime!!.clone() as Calendar 137 | var eTime = currentTime!!.clone() as Calendar 138 | 139 | if (period == DAILY) { 140 | currentBox!!.text = " [" + DateTimeStrategy.getSQLDateFormat(currentTime!!) + "] " 141 | currentBox!!.textSize = 16f 142 | } else if (period == WEEKLY) { 143 | while (cTime.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) { 144 | cTime.add(Calendar.DATE, -1) 145 | } 146 | 147 | var toShow = " [" + DateTimeStrategy.getSQLDateFormat(cTime) + "] ~ [" 148 | eTime = cTime.clone() as Calendar 149 | eTime.add(Calendar.DATE, 7) 150 | toShow += DateTimeStrategy.getSQLDateFormat(eTime) + "] " 151 | currentBox!!.textSize = 16f 152 | currentBox!!.text = toShow 153 | } else if (period == MONTHLY) { 154 | cTime.set(Calendar.DATE, 1) 155 | eTime = cTime.clone() as Calendar 156 | eTime.add(Calendar.MONTH, 1) 157 | eTime.add(Calendar.DATE, -1) 158 | currentBox!!.textSize = 18f 159 | currentBox!!.text = " [" + currentTime!!.get(Calendar.YEAR) + "-" + (currentTime!!.get(Calendar.MONTH) + 1) + "] " 160 | } else if (period == YEARLY) { 161 | cTime.set(Calendar.DATE, 1) 162 | cTime.set(Calendar.MONTH, 0) 163 | eTime = cTime.clone() as Calendar 164 | eTime.add(Calendar.YEAR, 1) 165 | eTime.add(Calendar.DATE, -1) 166 | currentBox!!.textSize = 20f 167 | currentBox!!.text = " [" + currentTime!!.get(Calendar.YEAR) + "] " 168 | } 169 | currentTime = cTime 170 | list = saleLedger!!.getAllSaleDuring(cTime, eTime) 171 | var total =BigDecimal.ZERO 172 | for (sale in list!!) 173 | total =total.add(sale.total) 174 | 175 | totalBox!!.text = total.toString() + "" 176 | showList(list) 177 | } 178 | 179 | override fun onResume() { 180 | super.onResume() 181 | // update(); 182 | // it shouldn't call update() anymore. Because super.onResume() 183 | // already fired the action of spinner.onItemSelected() 184 | } 185 | 186 | /** 187 | * Add date. 188 | * @param increment 189 | */ 190 | private fun addDate(increment: Int) { 191 | val period = spinner!!.selectedItemPosition 192 | if (period == DAILY) { 193 | currentTime!!.add(Calendar.DATE, 1 * increment) 194 | } else if (period == WEEKLY) { 195 | currentTime!!.add(Calendar.DATE, 7 * increment) 196 | } else if (period == MONTHLY) { 197 | currentTime!!.add(Calendar.MONTH, 1 * increment) 198 | } else if (period == YEARLY) { 199 | currentTime!!.add(Calendar.YEAR, 1 * increment) 200 | } 201 | update() 202 | } 203 | 204 | companion object { 205 | 206 | val DAILY = 0 207 | val WEEKLY = 1 208 | val MONTHLY = 2 209 | val YEARLY = 3 210 | } 211 | 212 | } 213 | -------------------------------------------------------------------------------- /ui/sale/SaleDetailActivity.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.ui.sale 2 | 3 | import android.annotation.SuppressLint 4 | import android.app.Activity 5 | import android.graphics.Color 6 | import android.graphics.drawable.ColorDrawable 7 | import android.os.Build 8 | import android.os.Bundle 9 | import android.view.MenuItem 10 | import android.view.View 11 | import android.widget.ListView 12 | import android.widget.TextView 13 | 14 | import com.ionob.pos.R 15 | import com.ionob.pos.domain.inventory.LineItem 16 | import com.ionob.pos.domain.sale.Sale 17 | import com.ionob.pos.domain.sale.SaleLedger 18 | import com.ionob.pos.db.NoDaoSetException 19 | 20 | /** 21 | * UI for showing the detail of Sale in the record. 22 | * @author Ionob Team 23 | */ 24 | class SaleDetailActivity : Activity() { 25 | 26 | private var totalBox: TextView? = null 27 | private var dateBox: TextView? = null 28 | private var lineitemListView: ListView? = null 29 | private var lineitemList: MutableList? = null 30 | private var sale: Sale? = null 31 | private var saleId: Int = 0 32 | private var saleLedger: SaleLedger? = null 33 | 34 | @SuppressLint("MissingSuperCall") 35 | public override fun onCreate(savedInstanceState: Bundle?) { 36 | 37 | try { 38 | saleLedger = SaleLedger.getInstance() 39 | } catch (e: NoDaoSetException) { 40 | e.printStackTrace() 41 | } 42 | 43 | saleId = Integer.parseInt(intent.getStringExtra("id")) 44 | sale = saleLedger!!.getSaleById(saleId) 45 | 46 | initUI(savedInstanceState) 47 | } 48 | 49 | 50 | /** 51 | * Initiate actionbar. 52 | */ 53 | @SuppressLint("NewApi") 54 | private fun initiateActionBar() { 55 | if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { 56 | val actionBar = actionBar 57 | actionBar!!.setDisplayHomeAsUpEnabled(true) 58 | actionBar.title = resources.getString(R.string.sale) 59 | actionBar.setBackgroundDrawable(ColorDrawable(Color.parseColor("#33B5E5"))) 60 | } 61 | } 62 | 63 | 64 | /** 65 | * Initiate this UI. 66 | * @param savedInstanceState 67 | */ 68 | private fun initUI(savedInstanceState: Bundle?) { 69 | super.onCreate(savedInstanceState) 70 | setContentView(R.layout.layout_saledetail) 71 | initiateActionBar() 72 | totalBox = findViewById(R.id.totalBox) as TextView? 73 | dateBox = findViewById(R.id.dateBox) as TextView? 74 | lineitemListView = findViewById(R.id.lineitemList) as ListView? 75 | } 76 | 77 | /** 78 | * Show list. 79 | * @param list 80 | */ 81 | private fun showList(list: List) { 82 | lineitemList 83 | for (line in list) { 84 | val add = lineitemList!!.add(line) 85 | } 86 | 87 | val sAdap = SalesProductAdapter(this,lineitemList,object:SalesProductAdapter.SalesAdapterCallback{ 88 | override fun onPlusClicked(data: LineItem?) { 89 | 90 | } 91 | 92 | override fun onMinusClicked(data: LineItem?) { 93 | 94 | } 95 | 96 | override fun onItemClicked(data: LineItem?) { 97 | 98 | } 99 | }) 100 | lineitemListView!!.adapter = sAdap 101 | } 102 | 103 | 104 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 105 | when (item.itemId) { 106 | android.R.id.home -> { 107 | this.finish() 108 | return true 109 | } 110 | else -> return super.onOptionsItemSelected(item) 111 | } 112 | } 113 | 114 | /** 115 | * Update UI. 116 | */ 117 | fun update() { 118 | totalBox!!.text = sale!!.total.toString() + "" 119 | dateBox!!.text = sale!!.endTime + "" 120 | showList(sale!!.allLineItem) 121 | } 122 | 123 | override fun onResume() { 124 | super.onResume() 125 | update() 126 | } 127 | } 128 | 129 | -------------------------------------------------------------------------------- /ui/sale/SaleFragment.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.ui.sale 2 | 3 | import java.util.ArrayList 4 | 5 | import android.annotation.SuppressLint 6 | import android.app.AlertDialog 7 | import android.content.res.Resources 8 | import android.os.Bundle 9 | import android.view.LayoutInflater 10 | import android.view.View 11 | import android.view.ViewGroup 12 | import android.widget.* 13 | 14 | import com.ionob.pos.R 15 | import com.ionob.pos.domain.inventory.LineItem 16 | import com.ionob.pos.domain.sale.Register 17 | import com.ionob.pos.db.NoDaoSetException 18 | import com.ionob.pos.ui.MainActivity 19 | import com.ionob.pos.ui.component.UpdatableFragment 20 | import com.ionob.pos.ui.sale.SalesProductAdapter.SalesAdapterCallback 21 | import kotlinx.android.synthetic.main.layout_sale.* 22 | import java.math.BigDecimal 23 | 24 | /** 25 | * UI for Sale operation. 26 | * @author Ionob Team 27 | */ 28 | @SuppressLint("ValidFragment") 29 | class SaleFragment 30 | /** 31 | * Construct a new SaleFragment. 32 | * @param 33 | */ 34 | (public val reportFragment: UpdatableFragment) : UpdatableFragment() { 35 | 36 | private var register: Register? = null 37 | private var saleList= ArrayList() 38 | private var saleListView: ListView? = null 39 | private var clearButton: Button? = null 40 | private var totalPrice: TextView? = null 41 | private var endButton: Button? = null 42 | private var res: Resources? = null 43 | private var noDataLayout:ViewGroup?=null 44 | var previousDistanceFromFirstCellToTop=0 45 | var selectedLine:LineItem?=null; 46 | 47 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { 48 | val view = inflater!!.inflate(R.layout.layout_sale, container, false) 49 | return view 50 | } 51 | 52 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 53 | super.onViewCreated(view, savedInstanceState) 54 | 55 | try { 56 | register = Register.getInstance() 57 | } catch (e: NoDaoSetException) { 58 | e.printStackTrace() 59 | } 60 | 61 | 62 | 63 | res = resources 64 | saleListView = view.findViewById(R.id.sale_List) as ListView 65 | totalPrice = view.findViewById(R.id.totalPrice) as TextView 66 | clearButton = view.findViewById(R.id.clearButton) as Button 67 | endButton = view.findViewById(R.id.endButton) as Button 68 | noDataLayout=view.findViewById(R.id.no_data_container) as ViewGroup 69 | initUI() 70 | } 71 | 72 | /** 73 | * Initiate this UI. 74 | */ 75 | private fun initUI() { 76 | 77 | //saleListView!!.onItemClickListener = OnItemClickListener { arg0, arg1, arg2, arg3 -> showEditPopup(arg1, arg2) } 78 | 79 | clearButton!!.setOnClickListener { 80 | val viewPager = (activity as MainActivity).viewPager 81 | // viewPager!!.currentItem = 1 82 | } 83 | 84 | endButton!!.setOnClickListener { v -> 85 | if (register!!.hasSale()) { 86 | showPaymetn(v) 87 | } else { 88 | Toast.makeText(activity?.baseContext, res!!.getString(R.string.hint_empty_sale), Toast.LENGTH_SHORT).show() 89 | } 90 | } 91 | 92 | clearButton!!.setOnClickListener { 93 | if (!register!!.hasSale() || register!!.getCurrentSale()!!.allLineItem.isEmpty()) { 94 | Toast.makeText(activity?.baseContext, res!!.getString(R.string.hint_empty_sale), Toast.LENGTH_SHORT).show() 95 | } else { 96 | showConfirmClearDialog() 97 | } 98 | } 99 | 100 | 101 | saleListView?.setOnScrollListener(object : AbsListView.OnScrollListener { 102 | 103 | override fun onScrollStateChanged(view: AbsListView, scrollState: Int) { 104 | 105 | } 106 | 107 | override fun onScroll(listview: AbsListView, firstVisibleItem: Int, visibleItemCount: Int, totalItemCount: Int) { 108 | 109 | /* Check if the first item is already reached to top.*/ 110 | val firstCell = listview.getChildAt(0) 111 | if(firstCell == null){ return } 112 | val distanceFromFirstCellToTop = listview.getFirstVisiblePosition() * firstCell.getHeight() - firstCell.getTop() 113 | if (distanceFromFirstCellToTop < previousDistanceFromFirstCellToTop) { 114 | (activity as MainActivity).showView() 115 | } else if (distanceFromFirstCellToTop > previousDistanceFromFirstCellToTop) { 116 | (activity as MainActivity).hideView() 117 | 118 | } 119 | previousDistanceFromFirstCellToTop = distanceFromFirstCellToTop 120 | 121 | 122 | } 123 | 124 | }) 125 | (activity as MainActivity)?.showView() 126 | } 127 | 128 | /** 129 | * Show list 130 | * @param list 131 | */ 132 | private fun showList(list: List) { 133 | saleList.clear() 134 | for (line in list) { 135 | 136 | val add = saleList?.add(line) 137 | } 138 | if(saleList!=null&&saleList.size>0) { 139 | noDataLayout?.visibility=View.GONE 140 | total_items.text=saleList?.size?.toString() 141 | (activity as MainActivity).udateBadge(saleList?.size) 142 | val sAdap = SalesProductAdapter(activity!!.baseContext, saleList,object: SalesAdapterCallback{ 143 | override fun onPlusClicked(data: LineItem?) { 144 | updateLine(data) 145 | } 146 | override fun onMinusClicked(data: LineItem?) { 147 | updateLine(data) 148 | } 149 | 150 | override fun onItemClicked(data: LineItem?) { 151 | selectedLine=data 152 | (activity as MainActivity)?.selectedLine=data 153 | (activity as MainActivity).toggleAttrBottomSheet() 154 | 155 | } 156 | }) 157 | saleListView!!.adapter = sAdap 158 | } 159 | else 160 | { 161 | noDataLayout?.visibility=View.VISIBLE 162 | } 163 | } 164 | 165 | /** 166 | * Try parsing String to double. 167 | * @param value 168 | * @return true if can parse to double. 169 | */ 170 | fun tryParseDouble(value: String): Boolean { 171 | try { 172 | java.lang.Double.parseDouble(value) 173 | return true 174 | } catch (e: NumberFormatException) { 175 | return false 176 | } 177 | 178 | } 179 | fun updateLine(lineItem: LineItem?) 180 | { 181 | register!!.updateItem( 182 | register?.getCurrentSale()?.id!!, 183 | lineItem!!, lineItem.quantity, 184 | lineItem.priceAtSale?: BigDecimal.ZERO) 185 | 186 | var amount=register?.total!!.subtract(register?.totaltax).toString() 187 | 188 | totalPrice!!.text = amount.toFormatedString() 189 | // totalPrice!!.text = register?.total.toString() 190 | net_amount?.text=register?.total?.subtract(register?.totalDiscount)?.toFormatedString() 191 | tax_amount?.text=(register?.totaltax)?.toFormatedString() 192 | } 193 | 194 | /** 195 | * Show edit popup. 196 | * @param anchorView 197 | * @param position 198 | */ 199 | fun showEditPopup(anchorView: View, position: Int) { 200 | val bundle = Bundle() 201 | bundle.putString("position", position.toString() + "") 202 | bundle.putString("sale_id", register!!.getCurrentSale()!!.id.toString() + "") 203 | bundle.putString("product_id", register!!.getCurrentSale()!!.getLineItemAt(position)!!.product?.id.toString() + "") 204 | val newFragment = EditFragmentDialog(this@SaleFragment, reportFragment) 205 | newFragment.arguments = bundle 206 | newFragment.show(fragmentManager, "") 207 | 208 | } 209 | 210 | /** 211 | * Show popup 212 | * @param anchorView 213 | */ 214 | fun showPaymetn(anchorView: View) { 215 | val bundle = Bundle() 216 | bundle.putString("edttext", totalPrice!!.text.toString()) 217 | val newFragment = PaymentFragmentDialog(this@SaleFragment, reportFragment) 218 | newFragment.arguments = bundle 219 | newFragment.show(fragmentManager, "") 220 | } 221 | 222 | override fun update() { 223 | if (register!!.hasSale()) { 224 | showList(register!!.getCurrentSale()!!.allLineItem) 225 | totalPrice!!.text = register?.total!!.subtract(register?.totaltax).toFormatedString() 226 | 227 | total_discount.text=register?.totalDiscount.toString() 228 | 229 | net_amount?.text=register?.total?.subtract(register?.totalDiscount)?.toFormatedString() 230 | 231 | tax_amount?.text=(register?.totaltax)?.toFormatedString() 232 | 233 | } else { 234 | showList(ArrayList()) 235 | totalPrice!!.text = "0.00" 236 | } 237 | } 238 | 239 | override fun onResume() { 240 | super.onResume() 241 | update() 242 | } 243 | 244 | /** 245 | * Show confirm or clear dialog. 246 | */ 247 | private fun showConfirmClearDialog() { 248 | val dialog = AlertDialog.Builder(activity) 249 | dialog.setTitle(res!!.getString(R.string.dialog_clear_sale)) 250 | dialog.setPositiveButton(res!!.getString(R.string.no)) { dialog, which -> } 251 | 252 | dialog.setNegativeButton(res!!.getString(R.string.clear)) { dialog, which -> 253 | register!!.cancleSale() 254 | update() 255 | } 256 | 257 | dialog.show() 258 | } 259 | 260 | } 261 | -------------------------------------------------------------------------------- /ui/sale/SalesProductAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.ui.sale 2 | 3 | import android.content.Context 4 | import android.preference.PreferenceManager 5 | import android.support.v4.app.FragmentActivity 6 | import android.util.Log 7 | import android.util.LogPrinter 8 | import android.view.LayoutInflater 9 | import android.view.View 10 | import android.view.ViewGroup 11 | import android.widget.* 12 | import com.ionob.pos.R 13 | import com.ionob.pos.domain.inventory.LineItem 14 | import com.ionob.pos.domain.inventory.Product 15 | import java.math.BigDecimal 16 | 17 | class SalesProductAdapter (private var context: Context, private var notesList: MutableList?,var callback:SalesAdapterCallback) : BaseAdapter() { 18 | 19 | private var mlayoutInflater:LayoutInflater?=null 20 | private var productList: MutableList?=null 21 | var haveOutOfstocks=false 22 | init { 23 | this.mlayoutInflater= LayoutInflater.from(context) 24 | } 25 | interface SalesAdapterCallback 26 | { 27 | fun onPlusClicked(data:LineItem?) 28 | fun onMinusClicked(data:LineItem?) 29 | fun onItemClicked(data:LineItem?) 30 | } 31 | 32 | override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View? { 33 | 34 | val view: View? 35 | val vh: ViewHolder 36 | 37 | if (convertView == null) { 38 | view = mlayoutInflater?.inflate(R.layout.cart_item_adapter, parent, false) 39 | vh = ViewHolder(view) 40 | view?.tag = vh 41 | Log.i("JSA", "set Tag for ViewHolder, position: " + position) 42 | } else { 43 | view = convertView 44 | vh = view.tag as ViewHolder 45 | } 46 | 47 | vh.name.text = notesList?.get(position)?.product?.name 48 | vh.qty.setText(notesList?.get(position)?.quantity?.toString()) 49 | vh.price.text = notesList?.get(position)?.priceAtSale.toString() 50 | var discount=notesList?.get(position)?.discount 51 | vh.lindeDiscount.text= discount.toString() 52 | vh.textTotalAmoutn.text = notesList?.get(position)?.totalAmount?.subtract(discount).toString() 53 | validateStock(position, vh) 54 | vh.qtyPlus.setOnClickListener { 55 | if(vh.qty.text.toString().isNullOrEmpty()||vh.qty.text.toString().equals("")) return@setOnClickListener 56 | if(validateStock(position,vh)) { 57 | var selectedLine = notesList?.get(position) 58 | selectedLine?.quantity = selectedLine?.quantity?.add(BigDecimal.ONE)!! 59 | vh.qty.setText(selectedLine?.quantity?.toString()) 60 | vh.textTotalAmoutn.setText(notesList?.get(position)?.totalAmount?.toString()) 61 | callback.onPlusClicked(selectedLine) 62 | } 63 | } 64 | vh.qtyMinus.setOnClickListener { 65 | if(vh.qty.text.toString().isNullOrEmpty()||vh.qty.text.toString().toBigDecimal().compareTo(BigDecimal.ZERO)<=0) { 66 | return@setOnClickListener 67 | } 68 | if(validateStock(position,vh)==true||validateStock(position,vh)==false) { 69 | var selectedLine = notesList?.get(position) 70 | selectedLine?.quantity = selectedLine?.quantity?.subtract(BigDecimal.ONE)!! 71 | if(selectedLine?.quantity.compareTo(BigDecimal.ZERO)<=0) 72 | { 73 | notesList?.get(position)?.discount= BigDecimal.ZERO 74 | var discount=notesList?.get(position)?.discount 75 | vh.lindeDiscount.text= discount.toString() 76 | } 77 | vh.qty.setText(notesList?.get(position)?.quantity?.toString()) 78 | vh.textTotalAmoutn.setText(notesList?.get(position)?.totalAmount?.toString()) 79 | callback.onMinusClicked(selectedLine) 80 | } 81 | 82 | } 83 | vh.itemContainer.setOnClickListener{ 84 | callback.onItemClicked(notesList?.get(position)) 85 | } 86 | 87 | return view 88 | } 89 | /*@return true if stock vailable*/ 90 | private fun validateStock(position: Int, vh: ViewHolder):Boolean { 91 | var stock = notesList?.get(position)?.product?.stockQty ?: BigDecimal.ZERO!! 92 | var qty = notesList?.get(position)?.quantity ?: BigDecimal.ZERO!! 93 | var isStockCheckenabled = PreferenceManager.getDefaultSharedPreferences(this.context).getBoolean(context.getString(R.string.key_check_stock), true) 94 | if (isStockCheckenabled) { 95 | if (stock?.minus(qty).signum()<=0 ) { 96 | vh.stock_text.text = stock.toString() 97 | vh.outofStockContainer.visibility = View.VISIBLE 98 | haveOutOfstocks = true 99 | return false 100 | } else { 101 | vh.outofStockContainer.visibility = View.GONE 102 | return true 103 | } 104 | } 105 | else 106 | { if ((stock?.minus(qty).signum()) <=0) { 107 | vh.stock_text.text = stock.toString() 108 | vh.outofStockContainer.visibility = View.VISIBLE 109 | } else { 110 | vh.outofStockContainer.visibility = View.GONE 111 | } 112 | return true 113 | } 114 | } 115 | 116 | override fun getItem(position: Int): Any? { 117 | return notesList!![position] 118 | } 119 | 120 | override fun getItemId(position: Int): Long { 121 | return position.toLong() 122 | } 123 | 124 | override fun getCount(): Int { 125 | return notesList?.size!! 126 | } 127 | } 128 | 129 | private class ViewHolder(view: View?) { 130 | val name: TextView 131 | val qty: EditText 132 | val price: TextView 133 | val qtyPlus: ImageView 134 | val qtyMinus: ImageView 135 | val itemContainer:LinearLayout 136 | val textTotalAmoutn:TextView 137 | val outofStockContainer:LinearLayout 138 | val stock_text:TextView 139 | val lindeDiscount:TextView 140 | 141 | init { 142 | this.name = view?.findViewById(R.id.cart_item_name) as TextView 143 | this.stock_text = view?.findViewById(R.id.stock_text) as TextView 144 | this.lindeDiscount = view?.findViewById(R.id.line_dicount) as TextView 145 | this.qty = view?.findViewById(R.id.cart_product_quantity) as EditText 146 | this.price = view?.findViewById(R.id.cart_price_text) as TextView 147 | this.qtyPlus = view?.findViewById(R.id.cart_plus_img) as ImageView 148 | this.qtyMinus = view?.findViewById(R.id.cart_minus_img) as ImageView 149 | this.itemContainer = view?.findViewById(R.id.item_container) as LinearLayout 150 | this.textTotalAmoutn=view?.findViewById(R.id.cart_total_price_text) as TextView 151 | this.outofStockContainer=view.findViewById(R.id.out_stock_layout) as LinearLayout 152 | } 153 | 154 | // if you target API 26, you should change to: 155 | // init { 156 | // this.tvTitle = view?.findViewById(R.id.tvTitle) as TextView 157 | // this.tvContent = view?.findViewById(R.id.tvContent) as TextView 158 | // } 159 | } -------------------------------------------------------------------------------- /ui/sale/adapter/CategoryAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.ui.sale.adapter 2 | 3 | /** 4 | * Created by yoonus on 2/16/2017. 5 | */ 6 | 7 | import android.annotation.SuppressLint 8 | import android.content.Context 9 | import android.graphics.Bitmap 10 | import android.graphics.BitmapFactory 11 | import android.icu.util.ULocale 12 | import android.support.v7.widget.RecyclerView 13 | import android.util.Log 14 | import android.view.LayoutInflater 15 | import android.view.MenuItem 16 | import android.view.MotionEvent 17 | import android.view.View 18 | import android.view.ViewGroup 19 | import android.widget.ImageView 20 | import android.widget.LinearLayout 21 | import android.widget.PopupMenu 22 | import android.widget.TextView 23 | import com.ionob.pos.R 24 | import com.ionob.pos.domain.inventory.Category 25 | import com.ionob.pos.ui.sale.model.CategoryModel 26 | import com.ionob.pos.utils.ListViewCallback 27 | 28 | 29 | import java.io.File 30 | 31 | 32 | class CategoryAdapter : RecyclerView.Adapter { 33 | private var categoryModels: List? = null 34 | var context: Context?=null 35 | var itemview: View?=null 36 | var TAG = this.javaClass.simpleName 37 | 38 | 39 | fun setData(data:List) 40 | { 41 | this.categoryModels=data 42 | notifyDataSetChanged() 43 | } 44 | 45 | inner class MyViewHolder(v: View) : RecyclerView.ViewHolder(v) { 46 | 47 | val categoryName: TextView 48 | 49 | 50 | init { 51 | 52 | categoryName = v.findViewById(R.id.txtTitle) as TextView 53 | 54 | } 55 | 56 | 57 | } 58 | 59 | fun showMenu(view: View, record: Any) { 60 | val menu = PopupMenu(context, view) 61 | val selectedObject = record as CategoryModel 62 | menu.setOnMenuItemClickListener { item -> 63 | val id = item.itemId 64 | 65 | true 66 | } 67 | 68 | 69 | 70 | 71 | } 72 | 73 | 74 | 75 | var adapterCallback:ListViewCallback?=null 76 | @JvmOverloads constructor(categoryModels: List, callback: ListViewCallback?, context: Context) { 77 | this.categoryModels = categoryModels 78 | try { 79 | this.adapterCallback = callback 80 | this.context = context 81 | 82 | } catch (e: ClassCastException) { 83 | throw ClassCastException("Activity must implement AdapterCallback.") 84 | } 85 | 86 | } 87 | 88 | 89 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder { 90 | 91 | itemview = LayoutInflater.from(parent.context) 92 | .inflate(R.layout.category_items_adapter, parent, false) 93 | return MyViewHolder(itemview!!) 94 | } 95 | 96 | @SuppressLint("ResourceAsColor") 97 | override fun onBindViewHolder(holder: MyViewHolder, position: Int) { 98 | 99 | // holder.rootLayout.setOrientation(isListView ? LinearLayout.HORIZONTAL : LinearLayout.VERTICAL); 100 | val eachItem = categoryModels!![position]// Offset for header 101 | holder.categoryName.setText(eachItem.name) 102 | itemview?.setOnClickListener { 103 | if (adapterCallback != null) 104 | adapterCallback!!.onItemClicked(eachItem) 105 | } 106 | 107 | itemview?.setOnLongClickListener { view -> 108 | // adapterCallback!!.onItemLongClick(eachItem) 109 | false 110 | } 111 | 112 | holder.itemView.setOnTouchListener { v, event -> false } 113 | 114 | } 115 | 116 | 117 | override fun getItemCount(): Int { 118 | // return categoryModels!!.size 119 | return categoryModels?.size?:0 120 | } 121 | 122 | 123 | 124 | } 125 | 126 | 127 | -------------------------------------------------------------------------------- /ui/sale/adapter/SalesRcordRecyclerViewAdapter.kt: -------------------------------------------------------------------------------- 1 | 2 | 3 | package com.ionob.pos.ui.sale.adapter 4 | 5 | import android.content.Context 6 | import android.support.v7.widget.RecyclerView 7 | import android.view.LayoutInflater 8 | import android.view.View 9 | import android.view.ViewGroup 10 | import android.widget.ImageView 11 | import android.widget.TextView 12 | import com.ionob.pos.R 13 | import com.ionob.pos.domain.sale.Sale 14 | import com.ionob.pos.ui.sale.model.SalesRecordModel 15 | 16 | class SalesRcordRecyclerViewAdapter(private val items: List, var context:Context, var onItemClick:OnItemClickListener,var onlongclicklistner:OnlongClickListener) 17 | : RecyclerView.Adapter(), View.OnClickListener ,View.OnLongClickListener{ 18 | 19 | 20 | 21 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { 22 | val v = LayoutInflater.from(parent.context).inflate(R.layout.sales_record_recycler, parent, false) 23 | v.setOnClickListener(this) 24 | v.setOnLongClickListener(this) 25 | return ViewHolder(v) 26 | } 27 | fun setLine(lines:List) 28 | { 29 | var data=(items as MutableList) 30 | data.clear() 31 | data.addAll(lines) 32 | notifyDataSetChanged() 33 | } 34 | 35 | override fun onBindViewHolder(holder: ViewHolder, position: Int) { 36 | val item = items[position] 37 | holder.itemView.setOnClickListener(View.OnClickListener { 38 | onItemClick.onItemClick(SalesRecordModel(item.id)) 39 | 40 | }) 41 | 42 | holder.itemView.setOnLongClickListener(View.OnLongClickListener { 43 | 44 | onlongclicklistner.onlongitemclickListener(SalesRecordModel(item.id)) 45 | true 46 | }) 47 | 48 | holder.text.text=item.id.toString() 49 | holder.netamount.text=item.subTotal?.toString() 50 | holder.paymentMode.text=item.paymentType 51 | } 52 | 53 | override fun getItemCount(): Int { 54 | return items.size //items.size 55 | } 56 | 57 | override fun onClick(v: View) { 58 | // onItemClickListener!!.onItemClick(v, v.tag as SalesRecordModel) 59 | } 60 | 61 | class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { 62 | var image: ImageView 63 | var text: TextView 64 | var netamount: TextView 65 | var paymentMode: TextView 66 | 67 | init { 68 | image = itemView.findViewById(R.id.image) as ImageView 69 | text = itemView.findViewById(R.id.text) as TextView 70 | netamount= itemView.findViewById(R.id.net_amount) as TextView 71 | paymentMode = itemView.findViewById(R.id.payment_mode) as TextView 72 | } 73 | } 74 | override fun onLongClick(p0: View?): Boolean { 75 | TODO("not implemented") //To change body of created functions use File | Settings | File Templates. 76 | } 77 | interface OnItemClickListener { 78 | 79 | fun onItemClick(viewModel: SalesRecordModel) 80 | 81 | } 82 | interface OnlongClickListener { 83 | 84 | fun onlongitemclickListener(viewModel: SalesRecordModel) 85 | 86 | } 87 | 88 | 89 | } 90 | -------------------------------------------------------------------------------- /ui/sale/model/CategoryModel.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.ui.sale.model 2 | 3 | 4 | class CategoryModel { 5 | 6 | var id: Int = 0 7 | var productCategoryId: Int = 0 8 | var name: String?=null 9 | var ImgUrl: String?=null 10 | var isActive: String?=null 11 | var instanceId: Int = 0 12 | } 13 | -------------------------------------------------------------------------------- /ui/sale/model/CustomerModel.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.ui.sale.model 2 | 3 | import android.os.Parcel 4 | import android.os.Parcelable 5 | import java.io.Serializable 6 | import java.util.ArrayList 7 | 8 | /**ionob*/ 9 | 10 | class CustomerModel ():Serializable 11 | 12 | { 13 | 14 | 15 | var id: Int = 0 16 | var customerName: String?=null 17 | var locationId: Int = 0 18 | var location: String? = null 19 | var customerId: Int = 0 20 | var customerCode: String? = null 21 | var email: String?=null 22 | var countryName: String?=null 23 | var city: String?=null 24 | var postalCode: String?=null 25 | var address1: String?=null 26 | var address2: String?=null 27 | var profileId: Int = 0 28 | var seaquenceNo: String? = null 29 | var isSelected:Boolean = false 30 | var isActive: Boolean = false 31 | var isNew: Boolean = false 32 | var status: String?=null 33 | var poPriceListId: Int = 0 34 | var soPriceListId: Int = 0 35 | var phone: String? = null 36 | var taxId: String?=null 37 | var isNoTax: Boolean = false 38 | var regionName: String?=null 39 | var stateCode: String?=null 40 | var isChecked: Boolean = false 41 | var isCustomer: Boolean = false 42 | var isVendor: Boolean = false 43 | var isEmployee: Boolean = false 44 | var isSalesRep: Boolean = false 45 | var bpGroupId: Int = 0 46 | var countryId: Int = 0 47 | var regionID: Int = 0 48 | 49 | 50 | val title: String 51 | get() = customerName + 52 | (if (customerCode != null) " ($customerCode)" else "") + 53 | if (location != null) "\n" + location!! else "" 54 | 55 | fun setIsChecked(isChecked: Boolean): Boolean { 56 | this.isChecked = isChecked 57 | return isChecked 58 | } 59 | 60 | fun getIsChecked(): Boolean { 61 | return isChecked 62 | } 63 | 64 | fun getName(): String? { 65 | return customerName 66 | } 67 | 68 | fun setName(name: String) { 69 | this.customerName = name 70 | } 71 | 72 | fun getRegionId(): Int { 73 | return regionID 74 | } 75 | 76 | fun setRegionId(regionId: Int) { 77 | this.regionID = regionId 78 | } 79 | 80 | 81 | 82 | 83 | override fun toString(): String { 84 | return "CustomerModel{" + 85 | "id='" + id + '\''.toString() + 86 | ", name='" + customerName + '\''.toString() + 87 | ", customerId=" + customerId + 88 | ", customerCode='" + customerCode + '\''.toString() + 89 | ", email='" + email + '\''.toString() + 90 | ", country='" + countryName + '\''.toString() + 91 | ", city='" + city + '\''.toString() + 92 | ", postalCode='" + postalCode + '\''.toString() + 93 | ", address1='" + address1 + '\''.toString() + 94 | ", address2='" + address2 + '\''.toString() + 95 | ", profileId=" + profileId + 96 | ", seaquenceNo=" + seaquenceNo + 97 | ", isSelected=" + isSelected + 98 | ", active=" + isActive + 99 | ", status='" + status + '\''.toString() + 100 | ", phone='" + phone + '\''.toString() + 101 | '}'.toString() 102 | } 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | companion object { 111 | 112 | } 113 | } 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /ui/sale/model/PriceListModel.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.ui.sale.model 2 | 3 | 4 | 5 | data class PriceListModel(var id:Int) { 6 | 7 | var priceListId: Int = 0 8 | var name: String?=null 9 | var description: String?=null 10 | var isEnforcePriceLimit: Boolean = false 11 | var currencyId: Int = 0 12 | var isSopriceList: Boolean = false 13 | var isTaxIncluded: Boolean = false 14 | var validFrom: Long = 0 15 | var stdPrecision: Int = 0 16 | var pricePrecision: Int = 0 17 | var isDefault: Boolean = false 18 | } 19 | -------------------------------------------------------------------------------- /ui/sale/model/SalesRecordModel.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.ui.sale.model 2 | 3 | 4 | import java.math.BigDecimal 5 | import java.util.Date 6 | 7 | data class SalesRecordModel(var id:Int) { 8 | 9 | var customerName: String? = null 10 | var customerCode: String?=null 11 | var customerId: Int = 0 12 | var salesRep: String?=null 13 | var invoiceDate: Date?=null 14 | var invoiceNo: String?=null 15 | var profileId: Int = 0 16 | var status: String?=null 17 | var subTotal: BigDecimal?= BigDecimal.ZERO 18 | var grandTotal: BigDecimal?=BigDecimal.ZERO 19 | var discountAmountt: BigDecimal?=BigDecimal.ZERO 20 | @Transient 21 | var isChecked: Boolean = false 22 | var bpLocationId: Int = 0 23 | var remoteRecordId: Int = 0 24 | var isPurchase: Boolean = false 25 | var priceListId: Int = 0 26 | var roundOff: BigDecimal?= BigDecimal.ZERO 27 | var errorMessage: String? = null 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /ui/sale/model/SalesTypes.java: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.ui.sale.model; 2 | 3 | 4 | public enum SalesTypes { 5 | POS, // include order invoice 6 | INVOICE_ONLY, 7 | ORDER_ONLY, // for order 8 | QUOTATION 9 | 10 | } 11 | -------------------------------------------------------------------------------- /ui/view/GridRecyclerView.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2014 Freddie (Musenkishi) Lust-Hed 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.ionob.pos.ui.view; 18 | 19 | import android.content.Context; 20 | import android.support.annotation.NonNull; 21 | import android.support.v7.widget.GridLayoutManager; 22 | import android.support.v7.widget.RecyclerView; 23 | import android.util.AttributeSet; 24 | import android.view.View; 25 | import android.view.ViewGroup; 26 | import android.view.animation.GridLayoutAnimationController; 27 | 28 | /** 29 | * An extension of RecyclerView, focused more on resembling a GridView. 30 | * Unlike {@link android.support.v7.widget.RecyclerView}, this view can handle 31 | * {@code } as long as you provide it a 32 | * {@link android.support.v7.widget.GridLayoutManager} in 33 | * {@code setLayoutManager(LayoutManager layout)}. 34 | *

35 | * Created by Freddie (Musenkishi) Lust-Hed. 36 | */ 37 | public class GridRecyclerView extends RecyclerView { 38 | 39 | public GridRecyclerView(Context context) { 40 | super(context); 41 | } 42 | 43 | public GridRecyclerView(Context context, AttributeSet attrs) { 44 | super(context, attrs); 45 | } 46 | 47 | public GridRecyclerView(Context context, AttributeSet attrs, int defStyle) { 48 | super(context, attrs, defStyle); 49 | } 50 | 51 | @Override 52 | public void setLayoutManager(LayoutManager layout) { 53 | if (layout instanceof GridLayoutManager) { 54 | super.setLayoutManager(layout); 55 | } else { 56 | throw new ClassCastException("You should only use a GridLayoutManager with GridRecyclerView."); 57 | } 58 | } 59 | 60 | @Override 61 | protected void attachLayoutAnimationParameters(View child, @NonNull ViewGroup.LayoutParams params, int index, int count) { 62 | 63 | if (getAdapter() != null && getLayoutManager() instanceof GridLayoutManager) { 64 | 65 | GridLayoutAnimationController.AnimationParameters animationParams = 66 | (GridLayoutAnimationController.AnimationParameters) params.layoutAnimationParameters; 67 | 68 | if (animationParams == null) { 69 | animationParams = new GridLayoutAnimationController.AnimationParameters(); 70 | params.layoutAnimationParameters = animationParams; 71 | } 72 | 73 | int columns = ((GridLayoutManager) getLayoutManager()).getSpanCount(); 74 | 75 | animationParams.count = count; 76 | animationParams.index = index; 77 | animationParams.columnsCount = columns; 78 | animationParams.rowsCount = count / columns; 79 | 80 | final int invertedIndex = count - 1 - index; 81 | animationParams.column = columns - 1 - (invertedIndex % columns); 82 | animationParams.row = animationParams.rowsCount - 1 - invertedIndex / columns; 83 | 84 | } else { 85 | super.attachLayoutAnimationParameters(child, params, index, count); 86 | } 87 | } 88 | } -------------------------------------------------------------------------------- /utils/CircleTransform.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2015 Antonio Leiva 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.ionob.pos.utils; 18 | 19 | import android.graphics.Bitmap; 20 | import android.graphics.BitmapShader; 21 | import android.graphics.Canvas; 22 | import android.graphics.Paint; 23 | 24 | import com.squareup.picasso.Transformation; 25 | 26 | /** 27 | * https://gist.github.com/julianshen/5829333 28 | */ 29 | public class CircleTransform implements Transformation { 30 | 31 | @Override 32 | public Bitmap transform(Bitmap source) { 33 | int size = Math.min(source.getWidth(), source.getHeight()); 34 | 35 | int x = (source.getWidth() - size) / 2; 36 | int y = (source.getHeight() - size) / 2; 37 | 38 | Bitmap squaredBitmap = Bitmap.createBitmap(source, x, y, size, size); 39 | if (squaredBitmap != source) { 40 | source.recycle(); 41 | } 42 | 43 | Bitmap bitmap = Bitmap.createBitmap(size, size, source.getConfig()); 44 | 45 | Canvas canvas = new Canvas(bitmap); 46 | Paint paint = new Paint(); 47 | BitmapShader shader = new BitmapShader(squaredBitmap, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP); 48 | paint.setShader(shader); 49 | paint.setAntiAlias(true); 50 | 51 | float r = size / 2f; 52 | canvas.drawCircle(r, r, r, paint); 53 | 54 | squaredBitmap.recycle(); 55 | return bitmap; 56 | } 57 | 58 | @Override 59 | public String key() { 60 | return "circle"; 61 | } 62 | } -------------------------------------------------------------------------------- /utils/Constance.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.utils 2 | 3 | import android.content.Context 4 | import android.content.SharedPreferences 5 | import android.os.Environment 6 | 7 | import com.ionob.pos.R 8 | import com.ionob.pos.app.AppController 9 | 10 | object Constance { 11 | 12 | val SELECTED_CUSTOMER="selected_customer" 13 | val UNDIFINED_CUSTOMER=-777 14 | val STANDARD_CUSTOMER=0 15 | } 16 | -------------------------------------------------------------------------------- /utils/FBCustomerDialog.kt: -------------------------------------------------------------------------------- 1 | package com.fitbae.fitness.dialogs 2 | 3 | import android.os.Bundle 4 | import android.support.v4.app.DialogFragment 5 | import android.text.Editable 6 | import android.text.TextWatcher 7 | import android.view.* 8 | import com.fitbae.fitness.adapter.FBCustomerDialogAdapter 9 | import com.ionob.pos.R 10 | import com.ionob.pos.ui.sale.model.CustomerModel 11 | import com.ionob.pos.utils.Constance 12 | import kotlinx.android.synthetic.main.dialog_select_customer.* 13 | import kotlinx.android.synthetic.main.header.* 14 | import kotlinx.android.synthetic.main.layout_main.* 15 | 16 | class FBCustomerDialog : DialogFragment(), View.OnClickListener { 17 | private var selectedCustomer: CustomerModel? = null 18 | private var customerList: MutableList? = null 19 | private var costomerAdapter: FBCustomerDialogAdapter? = null 20 | private var callBack:SelectCstomerCallback?=null 21 | 22 | 23 | override fun onCreate(savedInstanceState: Bundle?) { 24 | super.onCreate(savedInstanceState) 25 | 26 | } 27 | 28 | fun setCallback(callBack:SelectCstomerCallback) 29 | { 30 | this.callBack=callBack 31 | } 32 | override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, 33 | savedInstanceState: Bundle?): View? { 34 | dialog.requestWindowFeature(Window.FEATURE_NO_TITLE) 35 | return inflater.inflate(R.layout.dialog_select_customer, container, false) 36 | } 37 | 38 | private fun setListeners() { 39 | search_customer.addTextChangedListener(object : TextWatcher { 40 | override fun afterTextChanged(s: Editable?) { 41 | costomerAdapter?.let { 42 | it.filter(s.toString()) 43 | } 44 | } 45 | 46 | override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { 47 | } 48 | 49 | override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { 50 | } 51 | }) 52 | } 53 | 54 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 55 | super.onViewCreated(view, savedInstanceState) 56 | // try { 57 | // dialog.window!!.setBackgroundDrawable(ColorDrawable(Color.parseColor("#99000000"))) 58 | // } catch (e: Exception) { 59 | // e.printStackTrace() 60 | // } 61 | customerList= arrayListOf() 62 | var stdCustomerModel = CustomerModel() 63 | stdCustomerModel.customerId=Constance.STANDARD_CUSTOMER 64 | stdCustomerModel.customerName="Standard" 65 | stdCustomerModel.customerCode="std" 66 | stdCustomerModel.taxId="0" 67 | stdCustomerModel.isCustomer=true 68 | stdCustomerModel.email="No Email" 69 | stdCustomerModel.address1="No Address" 70 | 71 | var NoCustomerModel = CustomerModel() 72 | NoCustomerModel.customerId=Constance.UNDIFINED_CUSTOMER 73 | NoCustomerModel.customerName="No Customer" 74 | NoCustomerModel.customerCode="xx" 75 | NoCustomerModel.taxId="0" 76 | NoCustomerModel.isCustomer=true 77 | NoCustomerModel.email="No Email" 78 | NoCustomerModel.address1="No Address" 79 | customerList?.add(NoCustomerModel) 80 | customerList?.add(stdCustomerModel) 81 | arguments?.let { 82 | it.getSerializable("COSTOMER_LIST")?.let { 83 | customerList?.addAll(it as ArrayList) 84 | } 85 | it.getBoolean("CHANGE_COUNTRY")?.let { 86 | // isFromChangeCountry = it 87 | } 88 | } 89 | initViews() 90 | setListeners() 91 | } 92 | 93 | private fun initViews() { 94 | 95 | title_text.text="Search Customer" 96 | back.setOnClickListener { 97 | dismiss() 98 | } 99 | costomerAdapter = FBCustomerDialogAdapter((customerList as ArrayList?)!!, activity!!) 100 | customer_list.adapter = costomerAdapter 101 | costomerAdapter!!.setListner(object : FBCustomerDialogAdapter.OnItemSelected { 102 | 103 | override fun onItemSelected(selectedCustomer: CustomerModel) { 104 | 105 | costomerAdapter?.filter("") 106 | callBack!!.onSelectCustomer(selectedCustomer) 107 | dismiss() 108 | } 109 | }) 110 | back.setOnClickListener { dismiss() } 111 | } 112 | 113 | override fun onClick(v: View) { 114 | } 115 | 116 | 117 | 118 | interface SelectCstomerCallback { 119 | 120 | fun onSelectCustomer(customr:CustomerModel) 121 | fun onSelectedNoCustomer() 122 | 123 | } 124 | 125 | 126 | override fun onResume() { 127 | if (null != dialog && null != dialog.window) { 128 | val params = dialog.window!!.attributes 129 | params.width = android.view.WindowManager.LayoutParams.MATCH_PARENT 130 | params.height = WindowManager.LayoutParams.MATCH_PARENT 131 | dialog.window!!.attributes = params as android.view.WindowManager.LayoutParams 132 | dialog.setCanceledOnTouchOutside(false) 133 | dialog.window!!.setBackgroundDrawableResource(R.color.tranparent) 134 | // val wm = context!!.getSystemService(Context.WINDOW_SERVICE) as WindowManager // for activity use context instead of getActivity() 135 | // val display = wm.defaultDisplay // getting the screen size of device 136 | // val size = Point() 137 | // display.getSize(size) 138 | // val width = size.x /*- getDimen(context!!, R.dimen.margin_extra_large_xxx)*/ // Set your heights 139 | // val height = size.y /*- 100*/ // set your widths 140 | // val lp = WindowManager.LayoutParams() 141 | // lp.copyFrom(dialog.window!!.attributes) 142 | // lp.width = android.view.WindowManager.LayoutParams.MATCH_PARENT 143 | // lp.height = android.view.WindowManager.LayoutParams.MATCH_PARENT 144 | // dialog.window!!.attributes = lp 145 | } 146 | super.onResume() 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /utils/FBDatePickerFragment.kt: -------------------------------------------------------------------------------- 1 | package com.fitbae.fitness.dialogs 2 | 3 | import android.app.DatePickerDialog 4 | import android.app.Dialog 5 | import android.os.Bundle 6 | import android.support.v4.app.DialogFragment 7 | import android.widget.DatePicker 8 | import java.util.* 9 | 10 | /** 11 | * Created by Deepesh on 29-Jan-18. 12 | */ 13 | 14 | class FBDatePickerFragment : DialogFragment(), DatePickerDialog.OnDateSetListener { 15 | private var dateSelected: OnDateSelected? = null 16 | private var isDateOfBirth = false 17 | 18 | 19 | fun setOnDateSelected(onDateSelected: FBDatePickerFragment.OnDateSelected) { 20 | this.dateSelected = onDateSelected 21 | } 22 | 23 | fun setDateOfBirth(dateOfBirth: Boolean) { 24 | isDateOfBirth = dateOfBirth 25 | } 26 | 27 | override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { 28 | // Use the current date as the default date in the picker 29 | val c = Calendar.getInstance() 30 | val year = c.get(Calendar.YEAR) 31 | val month = c.get(Calendar.MONTH) 32 | val day = c.get(Calendar.DAY_OF_MONTH) 33 | val datePickerDialog = DatePickerDialog(activity, this, year, month, day) 34 | if (isDateOfBirth) { 35 | datePickerDialog.datePicker.maxDate = Calendar.getInstance().timeInMillis - 1000 36 | } else { 37 | datePickerDialog.datePicker.minDate = Calendar.getInstance().timeInMillis - 1000 38 | } 39 | 40 | return datePickerDialog 41 | } 42 | 43 | override fun onDateSet(view: DatePicker, year: Int, month: Int, dayOfMonth: Int) { 44 | dateSelected!!.onDateSelect(view, year, month + 1, dayOfMonth) 45 | } 46 | 47 | interface OnDateSelected { 48 | fun onDateSelect(view: DatePicker, year: Int, month: Int, dayOfMonth: Int) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /utils/IONPreferences.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.utils 2 | 3 | import android.content.Context 4 | import android.content.SharedPreferences 5 | import android.os.Environment 6 | 7 | import com.ionob.pos.R 8 | import com.ionob.pos.app.AppController 9 | 10 | object IONPreferences { 11 | 12 | 13 | 14 | val sharedAppPrefs: SharedPreferences 15 | get() = AppController.instance!!.getSharedPreferences(AppController.instance!!.getString(R.string.app_name), Context.MODE_PRIVATE) 16 | 17 | 18 | fun getSelectedCustomerId(): Int? { 19 | return sharedAppPrefs.getInt(Constance.SELECTED_CUSTOMER,Constance.UNDIFINED_CUSTOMER) 20 | } 21 | 22 | fun setSelectedCustomerId(selectedCustomerId:Int?) { 23 | sharedAppPrefs.edit().putInt(Constance.SELECTED_CUSTOMER,selectedCustomerId?:Constance.UNDIFINED_CUSTOMER).commit() 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /utils/IconMenuAdapter.kt: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.utils 2 | 3 | import android.content.Context 4 | import android.widget.TextView 5 | import android.content.Context.LAYOUT_INFLATER_SERVICE 6 | import android.view.LayoutInflater 7 | import android.view.View 8 | import android.view.ViewGroup 9 | import com.skydoves.powermenu.MenuBaseAdapter 10 | import android.graphics.drawable.Drawable 11 | import android.widget.ImageView 12 | import com.ionob.pos.R 13 | 14 | 15 | class IconMenuAdapter : MenuBaseAdapter() { 16 | 17 | override fun getView(index: Int, view: View?, viewGroup: ViewGroup): View { 18 | var view = view 19 | val context = viewGroup.context 20 | 21 | if (view == null) { 22 | val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater 23 | view = inflater.inflate(R.layout.title_menu, viewGroup, false) 24 | } 25 | 26 | val item = getItem(index) as IconPowerMenuItem 27 | val icon = view!!.findViewById(R.id.icon) as ImageView 28 | icon.setImageDrawable(item.icon) 29 | val title = view!!.findViewById(R.id.item_title) as TextView 30 | title.setText(item.title) 31 | return super.getView(index, view, viewGroup) 32 | } 33 | } 34 | 35 | class IconPowerMenuItem(public val icon: Drawable, public val title: String)// --- skipped setter and getter methods -------------------------------------------------------------------------------- /utils/ListViewCallback.java: -------------------------------------------------------------------------------- 1 | package com.ionob.pos.utils; 2 | 3 | 4 | public interface ListViewCallback { 5 | void onItemClicked(Object record); 6 | void onItemLongClick(Object record); 7 | } 8 | -------------------------------------------------------------------------------- /utils/RecordStatus.kt: -------------------------------------------------------------------------------- 1 | 2 | 3 | object RecordStatus 4 | { 5 | val NEW = "-1" 6 | val DRAFT = "0" 7 | val COMPLETED = "1" 8 | val SYNCED = "2" 9 | val INPROGRESS = "3" 10 | val sYNC_FAILED = "5" 11 | 12 | } --------------------------------------------------------------------------------