From bb169912fdfbc48d2968e27e93b3576e33c4ff6c Mon Sep 17 00:00:00 2001 From: Ondrej Oravcok Date: Wed, 20 Sep 2017 19:44:33 +0200 Subject: [PATCH] #73 updating fillUp - fuelVol+prices --- .../fuelup/data/provider/VehicleProvider.java | 231 ++++++++++++++---- .../screens/edit/EditFillUpActivity.java | 35 ++- 2 files changed, 210 insertions(+), 56 deletions(-) diff --git a/app/src/main/java/sk/piskula/fuelup/data/provider/VehicleProvider.java b/app/src/main/java/sk/piskula/fuelup/data/provider/VehicleProvider.java index e556228..97ba302 100644 --- a/app/src/main/java/sk/piskula/fuelup/data/provider/VehicleProvider.java +++ b/app/src/main/java/sk/piskula/fuelup/data/provider/VehicleProvider.java @@ -165,7 +165,7 @@ public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) { case EXPENSES: return validateExpenseAndInsert(uri, contentValues); case FILLUPS: - return validateFillUpAndInsert(uri, contentValues); + return validateFillUpAndInsertInTransaction(uri, contentValues, null); case VEHICLE_TYPES: return validateVehicleTypeAndInsert(uri, contentValues); default: @@ -185,7 +185,7 @@ public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String String[] expenseId = new String[] { String.valueOf(ContentUris.parseId(uri)) }; return db.delete(ExpenseEntry.TABLE_NAME, ExpenseEntry._ID + "=?", expenseId); case FILLUP_ID: - return deleteFillUpInTransaction(ContentUris.parseId(uri)); + return deleteFillUpInTransaction(ContentUris.parseId(uri), null); default: throw new IllegalArgumentException("Delete is not supported for " + uri); } @@ -208,18 +208,60 @@ public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Null private int validateFillUpAndUpdate(final Uri uri, final ContentValues contentValues, long id) { - validateFillUpBasics(contentValues, true); + validateFillUpBasics(contentValues, true, id); if (contentValues.containsKey(FillUpEntry.COLUMN_VEHICLE)) { throw new IllegalArgumentException("Cannot change vehicle of FillUp. Please, create a fresh new FillUp in this case."); } - final String selection = FillUpEntry._ID + "=?"; - final String[] idArgument = new String[] { String.valueOf(id) }; + boolean isDeleteAndInsertNeeded = contentValues.containsKey(FillUpEntry.COLUMN_DATE) + || contentValues.containsKey(FillUpEntry.COLUMN_FUEL_VOLUME) + || contentValues.containsKey(FillUpEntry.COLUMN_DISTANCE_FROM_LAST) + || contentValues.containsKey(FillUpEntry.COLUMN_IS_FULL_FILLUP); - getContext().getContentResolver().notifyChange(uri, null); - return mDbHelper.getWritableDatabase().update( - FillUpEntry.TABLE_NAME, contentValues, selection, idArgument); + if (!isDeleteAndInsertNeeded) { + // if only Not-Neighbour-Affecting values have been changed + final String selection = FillUpEntry._ID + "=?"; + final String[] idArgument = new String[] { String.valueOf(id) }; + + getContext().getContentResolver().notifyChange(uri, null); + return mDbHelper.getWritableDatabase().update( + FillUpEntry.TABLE_NAME, contentValues, selection, idArgument); + } else { + // if date, distance or fuelVolume have been changed, it may affect neighbouring fillUps + SQLiteDatabase db = mDbHelper.getWritableDatabase(); + db.beginTransactionNonExclusive(); + + FillUp fillUp = FillUpService.getFillUpById(id, getContext()); + + ContentValues recreatedValues = new ContentValues(); + recreatedValues.putAll(contentValues); + if (!recreatedValues.containsKey(FillUpEntry.COLUMN_VEHICLE)) + recreatedValues.put(FillUpEntry.COLUMN_VEHICLE, fillUp.getVehicle().getId()); + if (!recreatedValues.containsKey(FillUpEntry.COLUMN_DISTANCE_FROM_LAST)) + recreatedValues.put(FillUpEntry.COLUMN_DISTANCE_FROM_LAST, fillUp.getDistanceFromLastFillUp()); + if (!recreatedValues.containsKey(FillUpEntry.COLUMN_FUEL_VOLUME)) + recreatedValues.put(FillUpEntry.COLUMN_FUEL_VOLUME, fillUp.getFuelVolume().doubleValue()); + if (!recreatedValues.containsKey(FillUpEntry.COLUMN_FUEL_PRICE_PER_LITRE)) + recreatedValues.put(FillUpEntry.COLUMN_FUEL_PRICE_PER_LITRE, fillUp.getFuelPricePerLitre().doubleValue()); + if (!recreatedValues.containsKey(FillUpEntry.COLUMN_FUEL_PRICE_TOTAL)) + recreatedValues.put(FillUpEntry.COLUMN_FUEL_PRICE_TOTAL, fillUp.getFuelPriceTotal().doubleValue()); + if (!recreatedValues.containsKey(FillUpEntry.COLUMN_IS_FULL_FILLUP)) + recreatedValues.put(FillUpEntry.COLUMN_IS_FULL_FILLUP, fillUp.isFullFillUp() ? 1 : 0); + if (!recreatedValues.containsKey(FillUpEntry.COLUMN_DATE)) + recreatedValues.put(FillUpEntry.COLUMN_DATE, fillUp.getDate().getTime()); + if (!recreatedValues.containsKey(FillUpEntry.COLUMN_INFO)) + recreatedValues.put(FillUpEntry.COLUMN_INFO, fillUp.getInfo()); + + deleteFillUpInTransaction(id, db); + validateFillUpAndInsertInTransaction(uri, recreatedValues, db); + + db.setTransactionSuccessful(); + db.endTransaction(); + db.close(); + + return 1; + } } private int validateExpenseAndUpdate(final Uri uri, final ContentValues contentValues, long id) { @@ -421,7 +463,7 @@ private Uri validateExpenseAndInsert(Uri uri, ContentValues contentValues) { return ContentUris.withAppendedId(uri, id); } - private void validateFillUpBasics(ContentValues contentValues, boolean isUpdate) { + private void validateFillUpBasics(ContentValues contentValues, boolean isUpdate, Long existingFillUpId) { if (contentValues.containsKey(FillUpEntry.COLUMN_DISTANCE_FROM_LAST) || !isUpdate) { Long distance = contentValues.getAsLong(FillUpEntry.COLUMN_DISTANCE_FROM_LAST); @@ -454,10 +496,75 @@ private void validateFillUpBasics(ContentValues contentValues, boolean isUpdate) } } - if (fuelVolume != null || fuelPricePerLitre != null || fuelPriceTotal != null) { - if (fuelVolume == null || fuelPricePerLitre == null || fuelPriceTotal == null - || Math.abs(fuelPriceTotal - (fuelPricePerLitre * fuelVolume)) > ERROR) { - throw new IllegalArgumentException("Fuel priceTotal must equals (pricePerLitre * fuelVolume)"); + + if (isUpdate) { + /* we must handle three types of situations while updating + * - updating only fuelVolume -> we must update also PriceTotal + * - updating only pricePerLitre -> we have to update priceTotal + * - updating only priceTotal -> we have to update pricePerLitre + */ + FillUp updatingFillUp = FillUpService.getFillUpById(existingFillUpId, getContext()); + + if (fuelVolume != null || fuelPricePerLitre != null || fuelPriceTotal != null) { + // at least on of important value has changed + + // if only price changed + if (fuelVolume == null) { + fuelVolume = updatingFillUp.getFuelVolume().doubleValue(); + + // we must update price total if pricePerLitre changed + if (fuelPriceTotal == null) { + fuelPriceTotal = fuelPricePerLitre * fuelVolume; + contentValues.put(FillUpEntry.COLUMN_FUEL_PRICE_TOTAL, fuelPriceTotal); + } + + // we must update pricePerLitre if priceTotal changed + else if (fuelPricePerLitre == null) { + fuelPricePerLitre = fuelPriceTotal / fuelVolume; + contentValues.put(FillUpEntry.COLUMN_FUEL_PRICE_PER_LITRE, fuelPricePerLitre); + } + + // we must only check correctness if both prices changed + else { + if (Math.abs(fuelPriceTotal - (fuelPricePerLitre * fuelVolume)) > ERROR) { + throw new IllegalArgumentException("Fuel priceTotal must equals (pricePerLitre * fuelVolume)"); + } + } + } + + else if (fuelPriceTotal == null) { + // fuelVolume changed and fuelPriceTotal NOT + fuelPriceTotal = updatingFillUp.getFuelPriceTotal().doubleValue(); + + if (fuelPricePerLitre == null) { + throw new IllegalArgumentException("Cannot update fuelVolume without changing priceTotal or pricePerLitre."); + } else { + if (Math.abs(fuelPriceTotal - (fuelPricePerLitre * fuelVolume)) > ERROR) { + throw new IllegalArgumentException("Fuel priceTotal must equals (pricePerLitre * fuelVolume)"); + } + } + } + + else { + // fuelVol changed and priceTotal changed also + + if (fuelPricePerLitre == null) { + fuelPricePerLitre = updatingFillUp.getFuelPricePerLitre().doubleValue(); + } + + if (Math.abs(fuelPriceTotal - (fuelPricePerLitre * fuelVolume)) > ERROR) { + throw new IllegalArgumentException("Fuel priceTotal must equals (pricePerLitre * fuelVolume)"); + } + } + } + + } else { + // when inserting, all values must be filled + if (fuelVolume != null || fuelPricePerLitre != null || fuelPriceTotal != null) { + if (fuelVolume == null || fuelPricePerLitre == null || fuelPriceTotal == null + || Math.abs(fuelPriceTotal - (fuelPricePerLitre * fuelVolume)) > ERROR) { + throw new IllegalArgumentException("Fuel priceTotal must equals (pricePerLitre * fuelVolume)"); + } } } @@ -479,7 +586,7 @@ private void validateFillUpBasics(ContentValues contentValues, boolean isUpdate) } - private Uri insertFullValidatedFillUp(Uri uri, ContentValues contentValues) { + private Uri insertFullValidatedFillUp(Uri uri, ContentValues contentValues, SQLiteDatabase transaction) { long vehicleId = contentValues.getAsLong(FillUpEntry.COLUMN_VEHICLE); long timestamp = contentValues.getAsLong(FillUpEntry.COLUMN_DATE); @@ -516,14 +623,24 @@ private Uri insertFullValidatedFillUp(Uri uri, ContentValues contentValues) { BigDecimal avgOlderConsumption = existsOlderFullFillUp ? FillUpService.getConsumptionFromVolumeDistance(olderFuelUpsVol, olderFuelUpsDistance, unit) : null; Double avgOlderConsumptionDouble = avgOlderConsumption == null ? null : avgOlderConsumption.doubleValue(); + // we can already be in transaction, when e.g. updating fillUp + boolean isOutsideTransaction = transaction != null; + SQLiteDatabase db; + if (isOutsideTransaction) { + db = transaction; + } else { + db = mDbHelper.getWritableDatabase(); + db.beginTransactionNonExclusive(); + } + // insert new fillUp with fuel consumption contentValues.put(FillUpEntry.COLUMN_FUEL_CONSUMPTION, avgOlderConsumptionDouble); - SQLiteDatabase db = mDbHelper.getWritableDatabase(); - db.beginTransactionNonExclusive(); long id = db.insert(FillUpEntry.TABLE_NAME, null, contentValues); if (id == -1) { - db.endTransaction(); - db.close(); + if (!isOutsideTransaction) { + db.endTransaction(); + db.close(); + } Log.e(LOG_TAG, "Cannot insert FillUp."); throw new IllegalArgumentException("Cannot insert new FillUp."); } @@ -575,7 +692,8 @@ private Uri insertFullValidatedFillUp(Uri uri, ContentValues contentValues) { } cursorNewerFillUps.close(); - BigDecimal avgNewerConsumption = existsNewerFullFillUp ? FillUpService.getConsumptionFromVolumeDistance(newerFuelUpsVol, newerFuelUpsDistance, unit) : null; + BigDecimal avgNewerConsumption = !existsNewerFullFillUp ? null : + FillUpService.getConsumptionFromVolumeDistance(newerFuelUpsVol, newerFuelUpsDistance, unit); if (existsNewerFullFillUp) { // if newer full fillUp exists, compute consumption for all including that one full @@ -595,19 +713,30 @@ private Uri insertFullValidatedFillUp(Uri uri, ContentValues contentValues) { } } - db.setTransactionSuccessful(); - db.endTransaction(); - db.close(); + if (!isOutsideTransaction) { + db.setTransactionSuccessful(); + db.endTransaction(); + db.close(); + } getContext().getContentResolver().notifyChange(uri, null); return ContentUris.withAppendedId(uri, id); } - private Uri insertNotFullValidatedFillUp(Uri uri, ContentValues contentValues) { + private Uri insertNotFullValidatedFillUp(final Uri uri, final ContentValues contentValues, + final SQLiteDatabase transaction) { + + // we can already be in transaction, when e.g. updating fillUp + boolean isOutsideTransaction = transaction != null; + SQLiteDatabase db; + if (isOutsideTransaction) { + db = transaction; + } else { + db = mDbHelper.getWritableDatabase(); + db.beginTransactionNonExclusive(); + } // first insert fillUp - SQLiteDatabase db = mDbHelper.getWritableDatabase(); - db.beginTransactionNonExclusive(); long id = db.insert(FillUpEntry.TABLE_NAME, null, contentValues); long vehicleId = contentValues.getAsLong(FillUpEntry.COLUMN_VEHICLE); @@ -646,9 +775,11 @@ private Uri insertNotFullValidatedFillUp(Uri uri, ContentValues contentValues) { // if there is no newer full fill up, we do not compute consumption if (!existsNewerFullFillUp) { - db.setTransactionSuccessful(); - db.endTransaction(); - db.close(); + if (!isOutsideTransaction) { + db.setTransactionSuccessful(); + db.endTransaction(); + db.close(); + } getContext().getContentResolver().notifyChange(uri, null); return ContentUris.withAppendedId(uri, id); @@ -686,9 +817,11 @@ private Uri insertNotFullValidatedFillUp(Uri uri, ContentValues contentValues) { // if there is no older full fill up, we do not compute consumption if (!existsOlderFullFillUp) { - db.setTransactionSuccessful(); - db.endTransaction(); - db.close(); + if (!isOutsideTransaction) { + db.setTransactionSuccessful(); + db.endTransaction(); + db.close(); + } getContext().getContentResolver().notifyChange(uri, null); return ContentUris.withAppendedId(uri, id); @@ -714,15 +847,17 @@ private Uri insertNotFullValidatedFillUp(Uri uri, ContentValues contentValues) { new String[] { String.valueOf(fillUpId) }); } - db.setTransactionSuccessful(); - db.endTransaction(); - db.close(); + if (!isOutsideTransaction) { + db.setTransactionSuccessful(); + db.endTransaction(); + db.close(); + } getContext().getContentResolver().notifyChange(uri, null); return ContentUris.withAppendedId(uri, id); } - private int deleteFillUpInTransaction(final Long fillUpId) { + private int deleteFillUpInTransaction(final Long fillUpId, final SQLiteDatabase transaction) { FillUp fillUp = FillUpService.getFillUpById(fillUpId, getContext()); if (fillUp == null) { Log.e(LOG_TAG, "Cannot remove not existing fillUp (id=" + fillUpId + ")"); @@ -796,8 +931,14 @@ private int deleteFillUpInTransaction(final Long fillUpId) { ContentValues contentValuesUpdate = new ContentValues(); contentValuesUpdate.put(FillUpEntry.COLUMN_FUEL_CONSUMPTION, avgConsumption.doubleValue()); - SQLiteDatabase db = mDbHelper.getWritableDatabase(); - db.beginTransactionNonExclusive(); + boolean isOutsideTransaction = transaction != null; // we can already be in transaction, when e.g. updating fillUp + SQLiteDatabase db; + if (isOutsideTransaction) { + db = transaction; + } else { + db = mDbHelper.getWritableDatabase(); + db.beginTransactionNonExclusive(); + } int result = db.delete( FillUpEntry.TABLE_NAME, @@ -814,22 +955,24 @@ private int deleteFillUpInTransaction(final Long fillUpId) { new String[] { String.valueOf(id) }); } - db.setTransactionSuccessful(); - db.endTransaction(); - db.close(); + if (!isOutsideTransaction) { + db.setTransactionSuccessful(); + db.endTransaction(); + db.close(); + } return result; } - private Uri validateFillUpAndInsert(Uri uri, ContentValues contentValues) { + private Uri validateFillUpAndInsertInTransaction(Uri uri, ContentValues contentValues, SQLiteDatabase transaction) { - validateFillUpBasics(contentValues, false); + validateFillUpBasics(contentValues, false, null); boolean isFullFillUp = 1 == contentValues.getAsInteger(FillUpEntry.COLUMN_IS_FULL_FILLUP); if (isFullFillUp) { - return insertFullValidatedFillUp(uri, contentValues); + return insertFullValidatedFillUp(uri, contentValues, transaction); } else { - return insertNotFullValidatedFillUp(uri, contentValues); + return insertNotFullValidatedFillUp(uri, contentValues, transaction); } } diff --git a/app/src/main/java/sk/piskula/fuelup/screens/edit/EditFillUpActivity.java b/app/src/main/java/sk/piskula/fuelup/screens/edit/EditFillUpActivity.java index bedfa5d..7e9a9c5 100644 --- a/app/src/main/java/sk/piskula/fuelup/screens/edit/EditFillUpActivity.java +++ b/app/src/main/java/sk/piskula/fuelup/screens/edit/EditFillUpActivity.java @@ -43,8 +43,6 @@ public class EditFillUpActivity extends AppCompatActivity implements CompoundBut public static final String TAG = EditFillUpActivity.class.getSimpleName(); - public static final String EXTRA_FILLUP = "extra_fillup_to_update"; - private EditText mTxtDistance; private EditText mTxtFuelVolume; private TextView mTxtFuelVolumeUnit; @@ -165,21 +163,34 @@ public void onClickAdd(View view) { ContentValues contentValues = new ContentValues(); - contentValues.put(FillUpEntry.COLUMN_IS_FULL_FILLUP, isFull ? 1 : 0); - contentValues.put(FillUpEntry.COLUMN_DISTANCE_FROM_LAST, createdDistance); - contentValues.put(FillUpEntry.COLUMN_FUEL_VOLUME, createdFuelVol.doubleValue()); - contentValues.put(FillUpEntry.COLUMN_INFO, info.toString().trim()); + if (isFull != mSelectedFillUp.isFullFillUp()) + contentValues.put(FillUpEntry.COLUMN_IS_FULL_FILLUP, isFull ? 1 : 0); + + if (!createdDistance.equals(mSelectedFillUp.getDistanceFromLastFillUp())) + contentValues.put(FillUpEntry.COLUMN_DISTANCE_FROM_LAST, createdDistance); + + if (createdFuelVol.doubleValue() != mSelectedFillUp.getFuelVolume().doubleValue()) + contentValues.put(FillUpEntry.COLUMN_FUEL_VOLUME, createdFuelVol.doubleValue()); + + if (!info.toString().trim().equals(mSelectedFillUp.getInfo())) + contentValues.put(FillUpEntry.COLUMN_INFO, info.toString().trim()); if (priceMode == SwitchPrice.perVolume) { - contentValues.put(FillUpEntry.COLUMN_FUEL_PRICE_PER_LITRE, createdPrice.doubleValue()); - contentValues.put(FillUpEntry.COLUMN_FUEL_PRICE_TOTAL, VolumeUtil.getTotalPriceFromPerLitre( - createdFuelVol, createdPrice, mVehicle.getVolumeUnit()).doubleValue()); + if (!createdPrice.equals(mSelectedFillUp.getFuelPricePerLitre())) { + contentValues.put(FillUpEntry.COLUMN_FUEL_PRICE_PER_LITRE, createdPrice.doubleValue()); + contentValues.put(FillUpEntry.COLUMN_FUEL_PRICE_TOTAL, VolumeUtil.getTotalPriceFromPerLitre( + createdFuelVol, createdPrice, mVehicle.getVolumeUnit()).doubleValue()); + } } else { - contentValues.put(FillUpEntry.COLUMN_FUEL_PRICE_TOTAL, createdPrice.doubleValue()); - contentValues.put(FillUpEntry.COLUMN_FUEL_PRICE_PER_LITRE, VolumeUtil.getPerLitrePriceFromTotal( - createdFuelVol, createdPrice, mVehicle.getVolumeUnit()).doubleValue()); + if (!createdPrice.equals(mSelectedFillUp.getFuelPriceTotal())) { + contentValues.put(FillUpEntry.COLUMN_FUEL_PRICE_TOTAL, createdPrice.doubleValue()); + contentValues.put(FillUpEntry.COLUMN_FUEL_PRICE_PER_LITRE, VolumeUtil.getPerLitrePriceFromTotal( + createdFuelVol, createdPrice, mVehicle.getVolumeUnit()).doubleValue()); + } } + // TODO allow updating date + if (getContentResolver().update(ContentUris.withAppendedId(FillUpEntry.CONTENT_URI, mSelectedFillUp.getId()), contentValues, null, null) == 1) { Toast.makeText(getApplicationContext(), R.string.add_fillup_success_update, Toast.LENGTH_LONG).show(); setResult(RESULT_OK);