I have a small billing software written in php CodeIgniter. This is how i save values when i submit a payment
<?php
public function addPayment() {
$id = $this->input->post('id');
$client_id = $this->input->post('client_id');
$date = strtotime($this->input->post('date_from_addpayment'));
$description = $this->input->post('description');
$cash_pending = $this->input->post('cash_pending');
$cash_recevied = $this->input->post('cash_recevied');
$balance = $cash_pending - $cash_recevied;
?>
When each transaction occur I want to sum all the due of the client at that time and save it in balance table in MySQL.
My PHPMySQL structure of payment column is as follow:
https://i.stack.imgur.com/ELJrL.png
I just want when user ADD THE PAYMENT then balance due at that time display in this column.
Screenshot: https://i.imgur.com/raboF4M.png
To my understanding, balance, due, cash_pending - all 3 field relates - refers to the same figure - the amount that is pending. What i believe is you need to restructure the code for a bit.
You need to have a table maintaining clients balance (like current one you have). Just u can remove cash_pending / due fields.
You then need to have another table that will record in transactions of all the cash received. And as and when the cash is received, you can just substract that amount from the balance for the client.
In case any excess amount needs to be added for something like cash given or so - that you can add to the clients balance field back. So all the time - you have a proper balance figure for the client and also have a record of all the cash received from the user.
First of all before ending the php tag close your function's curly bracket.
In your table id is auto increment so do not need to take id as a input to store in database.
put all required fields as your table structure like this.
$data = array('client_id'=>$client_id, 'date'=>$date,
'description'=>$description, 'cash_recevied'=>$cash_recevied, 'cash_pending'=>$cash_pending,
'due'=>$due );
$this->load->model('Your-model-name');
$this->your-model-name->function-name($data);
Now call your model. and then in your model do this
function FunctionName($data){
return $this->db->insert('tablename', $data);
}
Related
I have a billing application, where I have a table for billings a table for billing numbering because the user can have more than one billing numbering and each numbering has its own consecutive, so when the user is going to create a billing he chooses the numbering, at the frontend the system shows the possible consecutive with which the billing will be created, is "possible" because if another user creates a billing before him, he will assign the consecutive. So the consecutive is finally assigned in the backend with this code:
...
$numbering = BillingNumbering::find($request->billing_numbering);
$number = $numbering->current_number + 1;
$billing->number = $number;
$numbering->current_number = $number;
$numbering->used = true;
$numbering->save();
$billing->save();
Where first I get the billing numbering, get the current number and increase in one and immediately update the table for future requests.
The problem is that some cases when multiples users are working and save a billing almost at the same time the billing take the same billing number generating duplicates in billing consecutives.
How can I achieve this without number duplication?
you can make the billing number unique. If I assume this is your real code. why you are saving 'numbering' first not 'billing'.
I am building a hotel style reservation system and I am loosing the way. I've got stuck at the exactly reservation moment when to add the reservation and I am concerned about come situations.
My flow is really easy, it lets multiple user to go through the reservation process for the same room until one of them press the reservation button before the others. The reservation information is kept in the session and is never stored in the db until somebody reach last step and press "book". In every step, the system check if the room/s is/are available if not it gives the error page.
Now the problem is preventing race condition combined to a last one mandatory check if still there are enough rooms left:
When user is in last step, he/she select the payment method and press book button. After checking if the selected payment option is ok (form data hasn't been altered) it redirects to the reservation controller where:
reservation controller
<?php
ReservationController extends JControllerLegacy{
public function placeReservation(){
//Do some checks to prevent direct access, booking existence and user completed all steps
$reservatioModel = $this ->getModel('Reservation')
if(!$reservationModel->placeReservation()){
//set errors and redirect to error page
return false;
}
//booking had been placed, passes the data to payment plugin
}
?>
and
Reservation model:
<?php
ReservationModel extends JModelLegacy{
public function placeReservation(){
//Get all variables and objects
//Lock the tables to prevent any insert while the last check
$db ->lockTable(#__bookings);
$db ->lockTable(#__booking_room);
//Perform the last mandatory check with tables locked to prevent read the table right one moment before another transaction insert the booking and allowing overbooking. THIS CHECK MUST BE 100% SURE NO ONE ELSE IS MANIPULATING/READING THE TABLE
if(!$this ->checkRoomsAvailability($data))
return false;
try{
$db ->transactionStart();
//Add the reservation in the booking table
if(!$this ->_saveBooking()){
$db ->rollBack();
return false;
}
//Add the room/s to the middle table #__booking_room
if(!$this -> _saveRooms())
$db ->rollBack();
return false;
}
$db ->transactionCommit();
}catch(Exception $e){
$db ->rollBack();
$this ->setError('We were not able to complete your reservation.');
return false;
}
$db ->unlockTables();
}
?>
The above mentioned tables are InnoDB, #__bookings hold the bookings and #__booking_room hold the information for the selected rooms (like avg_price, number of rooms, etc) and it has an foreign key to #__rooms and one to #__bookings
What am I concerned about?
1 - I am using other tables during the last availability check than the two locked and is giving me error.
2 - When the second user's execution arrives at the table locking point, does it wait until they get free or does it raise an error/exception? I could catch the exception and redirect user to the error page but locket table doesn't means reservation placed, it can occurs any issue while saving the information.
I hope my workflow is ok, please let me know if I am good to go or I should improve my code.
Thanks
EDIT:
To be mentioned, the business idea is like i.e. Expedia, booking, etc where you are allowed to select more rooms types and units per reservation. Indeed, my room table is not for specific/real room but is meant to be for room type with a fixed number of units available everyday if not already booked.
My approach would be simpler. In the table that stores the actual reservation, I would have a foreign key for the specific room being reserved, and have a UNIQUE index for the fields roomID, date. This will ensure that the same roomID cannot be recorded twice for the same date.
Next, when the customer confirms booking, I would run everything in a transaction as you're currently doing. When the code gets to the last place and tries to insert a new reservation, if a moment before another customer reserved that room, the DB will not allow you to insert another reservation for that room for that date. That's when I would either:
rollback and throw the error, or
try again with another room (with its own roomID) if there is another room of the same type still available
I can not say if your workflow aka business domain is the right choice as it depends on your business. But technically you want to have a booking transaction which also provides a check against double booking. The easiest way could be a room-booking-dates table with unique constraint on room is and date. So during your booking transaction you also insert each day with the room id into the table and the unique constraint will ensure that the second attempt will fail.
PS: If a table is locked, PHP will just wait for the unlock. No exception will be thrown (at least if the connection does not close after x seconds)
I am currently building a payment module which processes a customers account once a month. I have a query which gets all the customer payment items for the given month, sums the amount and then sends the data to the payment gateway. This works great and I receive back confirmation from the bank yes or no. If yes I then need to update all the items which were in the request with the invoice number. I am getting the sum using a while loop and this is performed before the request is sent. The gateway can only process a single request and I don't want to loop through each invoice item for each request, I would rather perform a single request for all outstanding invoice items.
Some code is:
$get_payment_items_query = mysql_query("SELECT * FROM tbl_invoice_item WHERE billing_cycle = date");
while($get_payment_items_result = mysql_fetch_assoc($get_payment_items_query)){
$invoice_amount = $invoice_amount + $get_payment_items_result['payment_amount'];
}
then later after I get the response back from the bank I am adding a record to the invoice table and getting the invoice id and then do:
$update_payment_item_query = mysql_query("UPDATE tbl_invoice_item SET status = '" . PAYMENTCOMPLETE . "', invoice_id = '$invoice_id' WHERE invoice_item_id = '" . $get_payment_items_result['invoice_item_id'] . "'");
This only updates a single record because the update query is outside the while loop. I know there is a way to store the record identifier in a string/array and perform a single update query but I don't really know the name for something like that so haven't been able to find an example.
I hope that makes sense but here is some more detail.
There are 5 items ready to be invoiced. I get the total amount of the 5 items. I then make a single request to the payment gateway to charge for the 5 items. The bank send back a response yes or no. If yes, I then generate an invoice id for the payment. I then need to update the 5 items with the newly created invoice id. The updating the 5 items in a single query is where I am stuck.
Thanks in advance.
I do not know if I understand your question right but you could use a sub-query in your where. Use the first query in where of second query:
WHERE invoice_item_id IN (SELECT invoice_item_id FROM tbl_invoice_item WHERE billing_cycle = date)
Found the solution. I am using a WHERE IN clause.
In the while loop I create a variable to hold the items which need to be updated
$invoice_item_id .= $get_payment_items_result['invoice_item_id'] . ',';
I then remove the last comma using substring_replace then in the update query I use
WHERE invoice_item_id IN (" . $invoice_item_array . ")
Seems to work OK.
I'm developing a simple invoice system using PHP and MySQL.
My initial thought was to use ID (auto incremented) for invoice ID. But that will not work.
A temporary invoice is created when user commits an order to my Payment Service Provider.
If the transaction fails, I need to delete the temporary invoice.
The problem is that the invoice has been created and given and ID - and by law, I'm not allowed to delete any invoices that has been given a invoice number. So I need to add another column 'invoice_id' and add an ID after successful transaction.
Multiple users may do a purchase at the same time.
My question is, how can I make sure to retrieve the last created invoice ID and increment this?
Should I use a $_SESSION[]for storing invoice_id? Or should I retrieve latest ID from DB? If retrieving from DB, should I lock the table for this transaction?
Any guidance much appreciated.
Create a temporary table for invoices which have not been processes.
Once the invoice has been processed, move over to permanent table and assign an invoice id using the AUTO_INCREMENT option in mysql
This will allow for two tables, one for unprocessed and the other for processed. You can also place an id field to keep track of the movement from temp -> perm
I wouldn't delete it, I would just cancel it. Additional usually after a failed transaction the trader reminds the customer to pay, which is not possible, when the invoice doesn't exist anymore.
One approach would be to keep the invoice in session until the payment has been approved. If the payment is not approved, the invoice will die with the user's session.
Another approach would be to create a holding table for pending invoices. When payment is approved, simply move the data into the invoice table.
And the last approach, go ahead and create the invoice in the invoice table, but soft delete it if the payment fails. Just set a flag, deleted = 1 and in all your procs add "where deleted = 0".
I would generate purely random invoice numbers. Simplest strategy:
md5(uniqid())
But still – storing unfinished invoices in the database sounds more sane.
Also the random factor will make guessing the invoice number more difficult.
I have a model called Invoice.I have made necessary CRUD for Invoice model.The attributes for the Invoice model are as like Invoice Title, Invoice No, Invoice Issue Date, Description.Now I want that when a user will redirect to invoice create page,the input field for Invoice No should be automatically filled in the create page with last inserted id +1 and it should have prefix like INV:.So the input field for Invoice No should be like this INV:12.By this a user don't need to fill the invoice no manually in increasing order.Here is the image for the create page.
First of all==>This is not a good idea to store Invoice number dependent on table's unique id
So you should insert last invoice number's number part+1 with text..
Now first get last invoice model then find its invoice number and populate the field..
In controller..
$model = new Invoice;
$last_invoice = Invoice::model()->find(array('order'=>'id DESC'));
$last_invoice_number = str_replace("INV:", "", $last_invoice->invoice_mumber);
$new_invoice_number = $last_invoice_number+1;
$model->invoice_number = "INV:".$new_invoice_number;
$this->render('create',array('model'=>$model));
EDIT:
Reason why Yii::app()->db->lastInsertId) cannot be used..
First as I said in first place its not good to dependent invoice id from unique id of table..second what if somebody inserted sonething in someother table in between..third what if the db connection is closed and started in between..
Just a Suggestion:
If user does not need to fill the invoice number then why don't you just skip it from Display. I mean let not show it while creating. Once the form is submitted, you can show all the submitted value along the invoice number.
Once the form is submitted, you can display the invoice number simply by $model -> id; where id is the invoice number in the database.
You could use invoice number as the primary auto increment bigint value in the database. Then use INV: prefix while display.
Hope it helps!
This is the simple way to get last insert id in Yii.
Yii::app()->db->getLastInsertId();