/*
* This program is part of the OpenLMIS logistics management information
* system platform software.
*
* Copyright © 2015 ThoughtWorks, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. This program is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Affero General Public License for more details. You should
* have received a copy of the GNU Affero General Public License along with
* this program. If not, see http://www.gnu.org/licenses. For additional
* information contact info@OpenLMIS.org
*/
package org.openlmis.core.model.repository;
import android.content.Context;
import android.database.Cursor;
import com.google.inject.Inject;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.stmt.Where;
import org.openlmis.core.LMISApp;
import org.openlmis.core.exceptions.LMISException;
import org.openlmis.core.model.KitProduct;
import org.openlmis.core.model.Product;
import org.openlmis.core.persistence.DbUtil;
import org.openlmis.core.persistence.GenericDao;
import org.openlmis.core.persistence.LmisSqliteOpenHelper;
import org.roboguice.shaded.goole.common.base.Function;
import org.roboguice.shaded.goole.common.collect.FluentIterable;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class ProductRepository {
GenericDao<Product> genericDao;
GenericDao<KitProduct> kitProductGenericDao;
@Inject
DbUtil dbUtil;
@Inject
public ProductRepository(Context context) {
genericDao = new GenericDao<>(Product.class, context);
kitProductGenericDao = new GenericDao<>(KitProduct.class, context);
}
public List<Product> listActiveProducts(final Product.IsKit isKit) throws LMISException {
List<Product> activeProducts = dbUtil.withDao(Product.class, new DbUtil.Operation<Product, List<Product>>() {
@Override
public List<Product> operate(Dao<Product, String> dao) throws SQLException {
return dao.queryBuilder().where().eq("isActive", true).and().eq("isKit", isKit.isKit()).query();
}
});
Collections.sort(activeProducts);
return activeProducts;
}
public List<Product> listProductsArchivedOrNotInStockCard() throws LMISException {
String rawSql = "SELECT * FROM products "
+ "WHERE isactive = '1' "
+ "AND products.iskit = '0' "
+ "AND (isarchived = '1' "
+ "OR id NOT IN ("
+ "SELECT product_id from stock_cards));";
final Cursor cursor = LmisSqliteOpenHelper.getInstance(LMISApp.getContext()).getWritableDatabase().rawQuery(rawSql, null);
List<Product> activeProducts = new ArrayList<>();
if (cursor.moveToFirst()) {
do {
Product product = new Product();
product.setActive(true);
product.setKit(false);
product.setPrimaryName(cursor.getString(cursor.getColumnIndexOrThrow("primaryName")));
product.setArchived(cursor.getInt(cursor.getColumnIndexOrThrow("isArchived"))!=0);
product.setCode(cursor.getString(cursor.getColumnIndexOrThrow("code")));
product.setId(cursor.getInt(cursor.getColumnIndexOrThrow("id")));
product.setStrength(cursor.getString(cursor.getColumnIndexOrThrow("strength")));
product.setType(cursor.getString(cursor.getColumnIndexOrThrow("type")));
activeProducts.add(product);
} while (cursor.moveToNext());
}
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
Collections.sort(activeProducts);
return activeProducts;
}
public void save(final List<Product> products) {
try {
dbUtil.withDaoAsBatch(Product.class, new DbUtil.Operation<Product, Void>() {
@Override
public Void operate(Dao<Product, String> dao) throws SQLException {
for (Product product : products) {
dao.create(product);
}
return null;
}
});
} catch (LMISException e) {
e.reportToFabric();
}
}
public void batchCreateOrUpdateProducts(final List<Product> productList) throws LMISException {
dbUtil.withDaoAsBatch(Product.class, new DbUtil.Operation<Product, Void>() {
@Override
public Void operate(Dao<Product, String> dao) throws LMISException {
for (Product product : productList) {
createOrUpdate(product);
}
return null;
}
});
}
//DON'T USE - THIS WILL BE PRIVATE WHEN KIT FEATURE TOGGLE IS ON
public void createOrUpdate(Product product) throws LMISException {
Product existingProduct = getByCode(product.getCode());
if (existingProduct != null) {
product.setId(existingProduct.getId());
product.setArchived(existingProduct.isArchived());
updateProduct(product);
} else {
genericDao.create(product);
}
createKitProductsIfNotExist(product);
}
public void updateProduct(Product product) throws LMISException {
genericDao.update(product);
}
private void createKitProductsIfNotExist(Product product) throws LMISException {
if (product.getKitProductList() != null && !product.getKitProductList().isEmpty()) {
for (KitProduct kitProduct : product.getKitProductList()) {
createProductForKitIfNotExist(kitProduct);
KitProduct kitProductInDB = queryKitProductByCode(kitProduct.getKitCode(), kitProduct.getProductCode());
if (kitProductInDB == null) {
kitProductGenericDao.create(kitProduct);
}
}
}
}
private void createProductForKitIfNotExist(KitProduct kitProduct) throws LMISException {
Product existingProduct = getByCode(kitProduct.getProductCode());
if (existingProduct == null) {
Product newProduct = new Product();
newProduct.setCode(kitProduct.getProductCode());
createOrUpdate(newProduct);
}
}
protected KitProduct queryKitProductByCode(final String kitCode, final String productCode) throws LMISException {
return dbUtil.withDao(KitProduct.class, new DbUtil.Operation<KitProduct, KitProduct>() {
@Override
public KitProduct operate(Dao<KitProduct, String> dao) throws SQLException {
return dao.queryBuilder().where().eq("kitCode", kitCode).and().eq("productCode", productCode).queryForFirst();
}
});
}
public List<KitProduct> queryKitProductByKitCode(final String kitCode) throws LMISException {
return dbUtil.withDao(KitProduct.class, new DbUtil.Operation<KitProduct, List<KitProduct>>() {
@Override
public List<KitProduct> operate(Dao<KitProduct, String> dao) throws SQLException {
return dao.queryBuilder().where().eq("kitCode", kitCode).query();
}
});
}
public Product getByCode(final String code) throws LMISException {
return dbUtil.withDao(Product.class, new DbUtil.Operation<Product, Product>() {
@Override
public Product operate(Dao<Product, String> dao) throws SQLException {
return dao.queryBuilder().where().eq("code", code).queryForFirst();
}
});
}
public Product getProductById(final long id) throws LMISException {
return dbUtil.withDao(Product.class, new DbUtil.Operation<Product, Product>() {
@Override
public Product operate(Dao<Product, String> dao) throws SQLException {
return dao.queryBuilder().where().eq("id", id).queryForFirst();
}
});
}
public List<Product> queryActiveProductsByCodesWithKits(final List<String> productCodes, final boolean isWithKit) throws LMISException {
return dbUtil.withDao(Product.class, new DbUtil.Operation<Product, List<Product>>() {
@Override
public List<Product> operate(Dao<Product, String> dao) throws SQLException {
Where<Product, String> queryBuilder = dao.queryBuilder().where().in("code", productCodes).and().eq("isActive", true).and().eq("isArchived", false);
if (!isWithKit) {
queryBuilder.and().eq("isKit", false);
}
return queryBuilder.query();
}
});
}
public List<KitProduct> queryKitProductByProductCode(final String productCode) throws LMISException {
return dbUtil.withDao(KitProduct.class, new DbUtil.Operation<KitProduct, List<KitProduct>>() {
@Override
public List<KitProduct> operate(Dao<KitProduct, String> dao) throws SQLException {
return dao.queryBuilder().where().eq("productCode", productCode).query();
}
});
}
public List<String> listArchivedProductCodes() throws LMISException {
List<Product> isArchived = dbUtil.withDao(Product.class, new DbUtil.Operation<Product, List<Product>>() {
@Override
public List<Product> operate(Dao<Product, String> dao) throws SQLException {
return dao.queryBuilder().selectColumns("code").where().eq("isArchived", true).query();
}
});
return FluentIterable.from(isArchived).transform(new Function<Product, String>() {
@Override
public String apply(Product product) {
return product.getCode();
}
}).toList();
}
public List<Product> queryProductsByProductIds(final List<Long> productIds) throws LMISException {
return dbUtil.withDao(Product.class, new DbUtil.Operation<Product, List<Product>>() {
@Override
public List<Product> operate(Dao<Product, String> dao) throws SQLException, LMISException {
return dao.queryBuilder().where().in("id", productIds).query();
}
});
}
public List<Product> queryActiveProductsInVIAProgramButNotInDraftVIAForm() throws LMISException {
String rawSql = "SELECT p1.* FROM products p1 "
+ "JOIN product_programs p2 "
+ "ON p1.code = p2.productCode "
+ "JOIN programs p3 "
+ "ON p2.programCode = p3.programCode "
+ "WHERE p3.programCode = 'VIA' OR p3.parentCode = 'VIA' "
+ "AND p2.isActive = 1 AND p1.isActive = 1 "
+ "AND p1.isKit = 0 "
+ "AND p1.id NOT IN "
+ "(SELECT product_id FROM rnr_form_items ri "
+ "WHERE ri.form_id IN "
+ "(SELECT id FROM rnr_forms r1 WHERE r1.emergency = 0 AND r1.status = 'DRAFT'))";
final Cursor cursor = LmisSqliteOpenHelper.getInstance(LMISApp.getContext()).getWritableDatabase().rawQuery(rawSql, null);
List<Product> products = new ArrayList<>();
if (cursor.moveToFirst()) {
do {
Product product = new Product();
product.setId(cursor.getLong(cursor.getColumnIndexOrThrow("id")));
product.setCode(cursor.getString(cursor.getColumnIndexOrThrow("code")));
product.setPrimaryName(cursor.getString(cursor.getColumnIndexOrThrow("primaryName")));
product.setStrength(cursor.getString(cursor.getColumnIndexOrThrow("strength")));
product.setType(cursor.getString(cursor.getColumnIndexOrThrow("type")));
product.setArchived(cursor.getInt(cursor.getColumnIndexOrThrow("isArchived")) == 1);
products.add(product);
} while (cursor.moveToNext());
}
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
return products;
}
public enum IsWithKit {
Yes(true),
No(false);
public boolean IsWithKit() {
return IsWithKit;
}
private boolean IsWithKit;
IsWithKit(boolean IsWithKit) {
this.IsWithKit = IsWithKit;
}
}
}