How to put flat rate before subtotal at checkout time in magento - magento-1.9

I want to put flat rate before subtotal which is by default below to subtotal.

How to add an additional Fee or Discount, or any kind of charge to order total of the magento checkout process
In a typical order, the order totals usually comprises of Sub Total, Shipping Cost, Taxes, Discount, based on these values the total order grand total is calculated.
This extra fee which we are adding to the total would reflect in the
Checkout Page Order Total,
Cart Page Order Total,
My Account Order View Page,
Print Order PDF,
Order EMails,
Admin Order View/Email/PDF,
Admin Invoice View/Email/PDF,
Admin Credit Memo View/Email/PDF.
Checkout Page Total Order Total Basics
We will see how to add the totals only to the checkout page. All the totals line items that show up the checkout page come from files located at folder Mage\Sales\Model\Quote\Address\Total.
In magento before order is placed all order data is stored in a quote object and after order is placed it gets transferred to the order object. The quote totals follow the collector pattern and we can add collector as many collector classes. To add collector to the quote object in our config.xml we add the lines
<global>
<sales>
<quote>
<totals>
<fee>
<class>fee/sales_quote_address_total_fee</class>
</fee>
</totals>
</quote>
</sales>
This means whenever the totals are calculated for a quote, it will also call this class.
All collectors are called from the collectTotals() function in the Quote Model.
In our collector class we put in the code
<?php class Excellence_Fee_Model_Sales_Quote_Address_Total_Fee
extends Mage_Sales_Model_Quote_Address_Total_Abstract{
protected $_code = 'fee';
public function collect(Mage_Sales_Model_Quote_Address $address)
{
parent::collect($address);
$this->_setAmount(0);
$this->_setBaseAmount(0);
$items = $this->_getAddressItems($address);
if (!count($items)) {
return $this; //this makes only address type shipping to come through
}
$quote = $address->getQuote();
if(Excellence_Fee_Model_Fee::canApply($address)){ //your business logic
$exist_amount = $quote->getFeeAmount();
$fee = Excellence_Fee_Model_Fee::getFee();
$balance = $fee - $exist_amount;
$address->setFeeAmount($balance);
$address->setBaseFeeAmount($balance);
$quote->setFeeAmount($balance);
$address->setGrandTotal($address->getGrandTotal() + $address->getFeeAmount());
$address->setBaseGrandTotal($address->getBaseGrandTotal() + $address->getBaseFeeAmount());
}
}
public function fetch(Mage_Sales_Model_Quote_Address $address)
{
$amt = $address->getFeeAmount();
$address->addTotal(array(
'code'=>$this->getCode(),
'title'=>Mage::helper('fee')->__('Fee'),
'value'=> $amt
));
return $this;
}
}
Here we are using two fields fee_amount and base_fee_amount, which contain our fee amount. We will have to see save these two fields to database, so in our module installer file we add this code
ALTER TABLE `".$this->getTable('sales/quote_address')."` ADD `fee_amount` DECIMAL( 10, 2 ) NOT NULL;
ALTER TABLE `".$this->getTable('sales/quote_address')."` ADD `base_fee_amount` DECIMAL( 10, 2 ) NOT NULL;
Order Page
Till now, all code written has been done only for the quote object. But after order is placed, we need to transfer all information to the order object. As you would have seen above we are using two fields fee_amount and base_fee_amount, we now need to store these two fields in the order table as well. To do all the above we need to do two things. First in the config.xml file add this code inside the global tab,
<fieldsets>
<sales_convert_quote_address>
<fee_amount><to_order>*</to_order></fee_amount>
<base_fee_amount><to_order>*</to_order></base_fee_amount>
</sales_convert_quote_address>
</fieldsets>
in our module install file
ALTER TABLE `".$this->getTable('sales/order')."` ADD `fee_amount` DECIMAL( 10, 2 ) NOT NULL;
ALTER TABLE `".$this->getTable('sales/order')."` ADD `base_fee_amount` DECIMAL( 10, 2 ) NOT NULL;

Related

Function modules to update table bsid (field: cession_kz)

For a certain program I need to update table bsid. The field cession_kz needs to be updated. I've looked for many function modules but none of them fit my needs. Does someone know a best practice to solve this problem?
BSID is a secondary index for BSEG customer items, so updating it directly will lead to database inconsistencies and any update must go via BSEG.
You can use a function module like FI_ITEMS_MASS_CHANGE. This FM updates BSEG by running a BDC for transaction FB02 (Change Document). When a relevant (customer) item is changed in BSEG, the corresponding BSID record is changed as well.
See example code below:
DATA: ls_bseg TYPE bseg,
lt_errdoc TYPE tpit_t_errdoc,
lt_fname TYPE tpit_t_fname,
lt_buztab TYPE tpit_t_buztab.
* Field name to be changed
APPEND 'CESSION_KZ' TO lt_fname.
* New field value
ls_bseg-cession_kz = 'AB'.
* Selection of items to be changed
* Only select customer items to avoid problems in batch input
SELECT bukrs belnr gjahr buzei koart umskz bschl mwart mwskz
FROM bseg
INTO CORRESPONDING FIELDS OF TABLE lt_buztab
WHERE belnr = '1400000000' AND
bukrs = '1000' AND
koart = 'D'. "Customers
CALL FUNCTION 'FI_ITEMS_MASS_CHANGE'
EXPORTING
s_bseg = ls_bseg
IMPORTING
errtab = lt_errdoc[]
TABLES
it_buztab = lt_buztab
it_fldtab = lt_fname
EXCEPTIONS
bdc_errors = 1
OTHERS = 2.
IF sy-subrc <> 0.
MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
ENDIF.
Make sure you allow changes in maintenance view V_TBAER with transaction SM30 or through customizing:
Financial Accounting → Financial Accounting Global Settings → Document → Line Item → Document Change Rules, Line Item.
Note:
Pledging indicators should be defined for all company codes passed to the FM:
Financial Accounting → Accouts Receivable and Accounts Payable → Customer Account → Master Data → Preperation for creating master data → Define Accounts Receivable Pledging Indicator.
If not, the field will not be available for the batch input and the FM will result in an error.

Spring MVC pagination - display all page numbers

the database user table is huge, it would take 15 mins to finish a select statement
so I am using this query:
select * from (
select * from user order by userId desc
) where ROWNUM > offset and ROWNUM <= offset + itemsPerPage;
then my DOA service method looks like
public List<User> getUserRange(int offset 1, limit itemsPerPage){
mybatis code
.....}
The user object
public class User{
String userName;
String userDOB;
String userAddress;
.....setters and getters
}
and I want to display it in a simple JSP page, my problem is most examples on the internet would need to retrieve the User List in a single select statement
but I want the JSP page to display all the page numbers and when user clicks each page number, the number gets passed into the getUserRange() method, a fresh list of users can be rendered.
I did look into some taglibs on the github, haven't got much luck, if anyone could point me to the right direction, would be much appreciated.
there are a few options:
I am not including any samples here, because you can find on each one of those libraries official webwite
the old fashioned way using the displayTag
<dependency>
<groupId>displaytag</groupId>
<artifactId>displaytag</artifactId>
<version>1.2</version>
</dependency>
which is a JSP oriented implementation doesn't utilizing new technologies such as Json, Jquery-UI, the development seems not so active
the popular way using the jquery-plugin datatables some say this is one of the most popular pagination plugin for the Java stack, currently very active, in my opinion offers most comprehensive features
<dependency>
<groupId>org.webjars</groupId>
<artifactId>datatables</artifactId>
<version>1.10.11</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>2.2.3</version>
</dependency>
the way I did it using another jquery-plugin jTable
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jTable</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery-ui</artifactId>
<version>1.11.4</version>
</dependency>
Comparisons:
both jTable and datatables are based on json and jquery, at the time of the post
it's very trendy thing to do, and better design compare to the old fashioned display tag
I found jTable is easier to understand, but datatables is more popular among my fellow developers. and I am certainly not recommend using any of the old fashioned displayTag technology
Webjars
if anyone of you wondering what webjars is, please take a look of this
in short it stops you manually download and dropping jquery.js or other JavaScript libs in your /webapp/WEB-INF/*** folder. by using Maven to manage
all your web dependencies.
Suggestions
Before I give my proposals, I want to suggest that you use Spring data repository. Just do some research on that, you will be amazed how much it helps you.
Answer to your question
SQL query
Your query smells like ORACLE query, I am not very good at that but it looks fine. For MySql-like users looking at this post, here is the query I will use:
SELECT * FROM user limit ?,? (first ? is offset, second is size)
Model (It is better to have an object that carry the page data around
Create a Pagination Class like so:
class Page{
private Integer offset; //offset
private Integer size; //how many items per page
private Integer currentPageNum; //current page number, 1 based
// default construction prohibited
private Page(){
}
Public Page(Integer currentPageNum, Integer size){
this.currentPageNum = currentPageNum;
this.size = size;
this.offset = currentPage * size - size; // important
}
// POJO methods ommitted
}
In your controller (e.g. servlets or spring controller)**
call a DAO's method getUsersCount() so that you will know the total number of items(users)
// total is used to find our exactly how many
// pages are there
// e.g. prev 1,2,3,4,5,6,7,8 next
// total is 8 in this case
Integer total = dao.getUserCount();
Integer size = getSizeFromUserInterface...// jsp, predefined, etc..
// find the page numbers 1,2,3,4,6,.. like above
Integer maxPageNum = total % size == 0 ? (total / size) : (total / size + 1);
// if total item count is 40, you have 40 users and
// every page shows 5 users, you will have 8 pages total
// according to the code above.
// now you can generate a Interger List that contains the 8
// page numbers from 1 through 8
List<Integer> pageNumList = //trivial ommited
Integer currentPage = getCurrentPageFromUserInterface...// user click on a page number on your website
Page page = new Page(currentPage, size);
// call another dao method to retrieve the user
// according to the page info gathered above
List<User> userList = dao.getUserRange(page.getOffSet, page.getSize);
// save the pageNumList and userList and page in request scope
// and forward to your jsp view, trivial.
request.set...
request.set...
request.set...
request.getRequestDispatcher("Your view").forward(request,response);
In your dest view
You will use the request scope's objects to show the page nav bar and the user list.
Initialization
You certainly need a controller to set default values of the page properties when the user list page first gets requested. e.g. pageNum is 1
Summary
This solution is by no means complete or perfect and it has a plenty of room to improve such as putting userList in Page as an attribute, make total number of items as a static member in page for the ease of later manipulation, but I think the idea will guide you to the right direction.
Here is the method to find out the total number of pages get the
total number of rows using
select count(*) as total_rows from table_name;
now call the below method
setTotal_pages("10",total_rows);
where 10 is the total number of content you want to display
public void setTotal_pages(int display_result,int total_rows) {
System.out.println("display_result :"+display_result+" total_rows "+total_rows);
int total_pages_temp = total_rows/display_result;
System.out.println("total_pages_temp "+total_pages_temp);
if(total_rows % display_result !=0){
System.out.println(" in if ");
total_pages_temp = total_pages_temp+1;
}
System.out.println("total_pages_temp "+total_pages_temp);
//return total_pages;
total_pages = total_pages_temp;
}
now below method will help to get the limit accoring to the
page_number let say user click on the hyper link page _number 2 now
to pass this 2 to method getStaringLimit
call the below method int get start_limit =
getStaringLimit('2','10'); this will give you the limit
//method using for pagination
public int getStaringLimit(int page_number,int display_counts){
if(page_number==1){
return 0;
}else{
//if p.no=2 then (2-1) = 1 then 1*10(where 10 is the display_counts)
//so 10 is the starting limit in pagenumber 2
return (page_number-1)*display_counts;
}
}
now you just have to run the query
select * from table_name limit start_limit,display_counts;
and you will get the result according to the page numbers
so fisrt you have to call setTotal_pages(int display_result,int
total_rows) this will return number of pages then set the value in
the hyperlink according to the pagenmber after that you have to cal
getStaringLimit(int page_number,int display_counts) it will return
starting limit so that you can execut the select query
select * from table_name limit start_limit,display_counts;
I will suggest you to use ajax when user clicks on the page number

Deleting record from database based on an action in a page

I am making an application for a car dealership. I have a page for stocks and a page for sales. Whenever I make a new entry in sales, I want the corresponding entry to be deleted from the stocks page.
My db for sales is
db.define_table('sales',
Field('customer_name','string'),
Field('village','string'),
Field('mobile_number','integer'),
Field('model','string',required=True,requires=IS_IN_SET(['1035DI','241DI','241DI(P.S.)','245DI','245DI(P.S.)','9000DI','9000DI(P.S)','5245DI','9500DI'])),
Field('engine_number','string'),
Field('chassis_number','string'),
Field('date_of_sale','date'),
Field('sale_price','integer'),
Field('bill_number','integer'),
Field('mode_of_payment','string',requires=IS_IN_SET(['Cash','Cheque']))
)
My db for stock is
db.define_table('stock',
Field('model','string',required=True,requires=IS_IN_SET(['1035DI','241DI','241DI(P.S.)','245DI','245DI(P.S.)','9000DI','9000DI(P.S)','5245DI','9500DI'])),
Field('engine_number','string',required=True),
Field('chassis_number','string',required=True),
Field('invoice_number','integer',required=True),
)
Engine number and chassis number is unique for each entry.
You didn't post any controller code, so I'm just making a simple untested example. I'm assuming you're using SQLFORM, and your sales controller function is just named "sales"
#controller, i.e. default.py
def sales():
form = SQLFORM(db.sales)
if form.process().accepted:
engine_number = form.vars.engine_number
chassis_number = form.vars.chassis_number
db((db.stock.engine_number == engine_number) & (db.stock.chassis_number == chassis_number)).delete()
return dict(form=form)

Opencart + unique product with options + stock control

I make bracelets and place them in my opencart store. Each bracelet is unique, so I have 1 in stock. But customer has to let me know the size of his/her wrist so I can adapt it.
Options ask me for quantities. So, I can not use them because I must enter a number or the option does not become visible.
What I need is:
bracelet B ---> tell me your wrist´s size: (here a drop down or a text box to let the customer choose or write).
Order will reads: Bracelet B... Size: 18cm.... xx $
Then, when the customer pays, Bracelt B is out of stock.
Now, I can do all that, but any time a customer adds an option, the bracelet keeps available.
So Order reads:
Bracelet B ... Size: 18cm... xx$
Bracelet B ... Size: 19cm... xx$ etc
function addToCart(product_id, quantity) {
quantity = typeof(quantity) != 'undefined' ? quantity : 1;
$.ajax({
url: 'index.php?route=checkout/cart/add',
type: 'post',
data: 'product_id=' + product_id + '&quantity=' + quantity,
dataType: 'json',
success: function(json) {
$('.success, .warning, .attention, .information, .error').remove();
if (json['redirect']) {
location = json['redirect'];
}
if (json['success']) {
$('#notification').html('<div class="success" style="display: none;">' + json['success'] + '<img src="catalog/view/theme/default/image/close.png" alt="" class="close" /></div>');
$('.success').fadeIn('slow');
$('#cart-total').html(json['total']);
$('html, body').animate({ scrollTop: 0 }, 'slow');
}
/*adding Shadyyx solution*/
if (json['error']) {
$('#notification').html('<div class="error" style="display: none;">' + json['error'] + '<img src="catalog/view/theme/default/image/close.png" alt="" class="close" /></div>');
$('html, body').animate({ scrollTop: 0 }, 'slow');
$('.error').fadeIn('slow');
}
/*end adding*/
}
});
}
In default OC You have the ability to disable ordering of out of stock products.
Simply go to the administration -> System -> Settings, click edit on Your store and navigate to the Options tab. Then scroll down to the Stock section and notice the Stock Checkout: option. If You select No and save the users won't be able to order the products that are not in stock.
This means that if You create a bracelet product with 1 piece in stock, add an option to it with one piece in stock and somebody order this one, it's stock will be immediately set to Not in stock and nobody will be able to order it again.
If You'd like to hide all the products that are not in stock after they are ordered, You have two options - either do this manually by disabling the product or You'd need to implement few modifications in to the getProducts() method for the product model to load only those products that are still in stock.
UPDATE regarding the comment: You are misunderstaning the options in OpenCart. One option for which You have the stock 1 piece is the size option, which may have different values, e.g. 15cm, 16cm, 17cm, 18cm, etc. All these values contained in one single size option for one single stock item mean that if I select any of them, after ordering the bracelet there will no more pieces left.
What You are telling is creating one option for 15cm with 1pcs stock, another option for 16cm with 1pcs stock, etc., thus having 1 piece in stock for each size - this is incorrect (i.e. misuse of product options). Nevertheless, even in this case, when different sizes have all one piece but the product itself has only one piece, after ordering first it should be out of the stock even there are options with stock left...
Step by step walkthrough:
Go to Your OC administration and log in.
Hover the mouse over the Catalog menu point and click on the Options entry
On this Options overview screen notice the Insert in the top-right corner - click it
Enter the Option's name, e.g. Wrist Size
Choose the Option's type, either Select or Radio (depending on how many possible values You want to have, more than 4, use Select)
Sort Order may be a numeric value (or when blank, will be filled with 0)
Now there is empty table underneath with one row containing only a button Add Option Value - by clicking this it will add a row with empty form fields to enter the Option's value; let's say we want to add wrist sizes from 15cm to 22cm => 8 values => click that button 8 times (be careful, after each click it will be moved downward as a new row with form fields will appear above it)
into that 8 rows enter all the necessary values, e.g. 15cm, 16cm, ..., 22cm as value's name and sort order to match Your needs (leaving blank may lead to inappropriately ordered values when displayed)
Click on Save button located at top-right corner.
Now navigate Yourself to the products overview, select the product You want to add this option to and click Edit in that row. Move to the Data tab and make sure the bracelet has these settings:
Quantity: 1
Subtract Stock: Yes
Out of Stock Status: Out of Stock
Then move to the Option tab and add the new option by typing the Option's name (Wrist Size) in the left area - after the Option is found, click on that label and a new Option (new tab) will be added to the view. Now make sure the Option is required and add all possible values while setting these settings to all of them:
Quantity: 1
Subtract Stock: Yes
The other option values depends on Your business model. Now Save the product and try to order it with any of the wrist sizes value. If You have the settings set for the store that the customer isn't possible to order the products that are out of stock, this should work for You.
Let me know if there is something that I missed (or if it still doesn't work).
UPDATE:
Here is one possible solution (not tested but I believe it will work out of the box or maybe there is only simple bug You may fix Yourself):
Open up the catalog/controller/checkout/cart.php and find this line (should be at 543):
$this->cart->add($this->request->post['product_id'], $quantity, $option);
and before this line directly add this code (You may want to do this via vQmod extension):
if ($product_info['quantity'] == 1 && $product_info['subtract'] == 1) {
$products = $this->cart->getProducts();
$already_added = false;
foreach ($products as $product) {
if ($product['product_id'] == $this->request->post['product_id']) {
$already_added = true;
break;
}
}
if ($already_added) {
return $this->response->setOutput(json_encode(array(
'error' => $this->language->get('text_product_already_added')
)));
}
}
Then open up this file catalog/language/english/checkout/cart.php and add this to the end:
$_['text_product_already_added'] = 'This product has allowed quantity of 1 piece and is already added to a cart. Remove it from the cart to be able to add it (e.g. with different size).';
This is all only as an example, You may edit the error message to meet Your requirements.
Warning: this is only a simple solution not letting the same user (or within the same session) to add the same product twice or more times into the cart but it won't prevent the same product being added and ordered at the very same time by two different users (or one user using two browsers, for example). For this edge case You'd need to implement some kind of product locking - after it is added to cart this is saved to a DB and nobody else would be able to add the same product into the cart. In this case it would be nice to store also the datetime when it was locked and have a cron job that will unlock this product (also with removing from the cart) so that the product is not locked for ever and is orderable by other users again...
EDIT for JS part:
Open up this file catalog/view/javascript/common.js and search for method function addToCart(product_id, quantity) { - in this file find this part:
if (json['success']) {
...
}
and after this one add this code:
if (json['error']) {
$('#notification').html('<div class="error" style="display: none;">' + json['error'] + '<img src="catalog/view/theme/default/image/close.png" alt="" class="close" /></div>');
$('html, body').animate({ scrollTop: 0 }, 'slow');
$('.error').fadeIn('slow');
}
This should be enough.
UPDATE XYZ:
In PHP find this code what have we added:
return $this->response->setOutput(json_encode(array(
'error' => $this->language->get('text_product_already_added')
)));
and change it to this (then try):
$this->response->setOutput(json_encode(array(
'error' => $this->language->get('text_product_already_added')
)));
return;
The point is to see in console where the request is done to index.php?route=checkout/cart/add the response with either success or error message in response. Try for both cases to make sure You are looking at the correct request (in success You can see the success message on the top of page so You may be sure it was done) and then try again to receive error (for the same product) message - it should be contained in the response the same way as the success message is. If still doesn't work, try to change return; to exit;...
Unfortunately I can't comment your post.
I had the problem with error message not showing up, when trying to add the product twice.
I needed to add the JS code to /catalog/view/theme/*/product/product.tpl
Just search for "url: 'index.php?route=checkout/cart/add'" and add the code shadyxx postet right after
if (json['success']) { ... }

Creating a user generated list in flash

I'm trying to create a flash application that will keep track of user generated values. The app should basically allow the user to input the name of the item and it's cost. The total costs should then be added up to show a total value to the user. I can probably figure out how to add the values together, but I'm not really sure how to allow the user to create a list and then allow the user to save it. Can anyone point me towards a tutorial or point me in the right direction?
I am using variables to add user inputed numbers to come up with a total. The first problem is that actionscript 3.0 does not allow variables for texts. I just converted it to 2.0 to fix this. The second problem, is when I test the app and put in my values and click submit, I get NaN in the total values field. Is there a reason why it wouldn't add the values?
Here is the code I used for the submit button:
on (release) {
total = Number(rent) + Number(food) + Number(travel) + Number(entertainment) + Number(bills);
}
Am I missing anything?
Can I give the input text instance names and then give them variables? How are some ways to go about this?
Thanks for the help!
Have an object array, say for example
var stack:Array = new Array();
Then push the item name and it's cost to that array when user inputs, like
stack.push({item:AAA, cost:xx});
So that you can generate the list whenever you want with that array.
You have to see how this works in code. A list in actionscript could be stored inside an array, vector, dictionary or even an Object.
Var myList:Array = [];
myList.push({name: "item 1", cost: 5 });
myList.push({name: "item 2", cost: 7.5 });
If you want to grab the 'product' of "item 1" from the list, you have to create a function for that, lets call it getProductByName
function getProductByName(name:String):Object
{
for each(var product:Object in myList)
{
if (product.name === name) return product;
}
return null; // no match found
}
You can call that function like this:
var product = getProductByName("item 1");
trace(product.cost); // 5
And you can alter the product, so lets make it more expensive
product.cost += 1;
trace(product.cost); // 6
Have fun! If you are using classes, you would create one for the product, with public name and cost, and in that case you'de better use a vector, to ensure working with the right type.
This is what fixed the issue for me in action script 3.0:
myButton.addEventListener(MouseEvent.CLICK, addThem);
function addThem(e:MouseEvent)
{
totalField.text = String ( Number(field1.text) + Number(field2.text) + ....);
}
I also had to name the instances appropriately.