Merge branch 'credit-notes'

Conflicts:
	includes/abstracts/abstract-wc-order.php
	includes/class-wc-order-factory.php
	includes/class-wc-post-types.php
	includes/wc-formatting-functions.php
	includes/wc-order-functions.php
This commit is contained in:
Mike Jolley 2014-07-29 12:09:52 +01:00
commit c465c7235d
56 changed files with 5022 additions and 3225 deletions

File diff suppressed because one or more lines are too long

View File

@ -598,259 +598,105 @@ ul.wc_coupon_list_block {
padding: 0;
background: #fefefe;
}
.bulk_actions {
float:left;
padding-left: 12px;
.wc-order-data-row {
border-bottom:1px solid #DFDFDF;
background: #fff;
padding: 12px;
background:#f8f8f8;
.clearfix;
line-height: 2em;
text-align: right;
p {
margin: 0;
line-height: 2em;
}
}
.wc-order-bulk-actions {
background: #fefefe;
vertical-align: top;
border-top: 0;
select {
vertical-align: top;
}
.add_items {
float:right;
padding-right: 12px;
p.bulk-actions {
float: left;
}
}
.wc-order-add-item {
background: #fff;
vertical-align: top;
border-top: none;
.add_item_id, .chosen-container {
margin-right: 9px;
vertical-align: top;
float:left;
.search-field input {
min-width: 100px;
}
}
button {
margin: 2px 0 0 0;
}
}
.add_meta {
margin-left:0 !important;
}
h3 small {
color: #999;
}
a.edit_order_item {
opacity: 0.4;
&:hover, &:focus {
opacity: 1;
}
}
}
#woocommerce-order-downloads {
.buttons {
float:left;
padding: 0;
margin: 0;
vertical-align: top;
.add_item_id, .chosen-container {
.chosen-container {
width: 400px !important;
margin-right: 9px;
text-align: left;
}
.cancel-action,
.save-action,
.calculate-action {
float: left;
margin-right: 2px;
}
}
.wc-used-coupons {
float: left;
width: 50%;
}
.wc-order-totals {
float: right;
width: 50%;
margin: 0;
padding: 0;
.amount {
font-weight: bold;
}
.label {
vertical-align: top;
float:left;
}
button {
margin: 2px 0 0 0;
}
}
h3 small {
color: #999;
}
}
#poststuff #woocommerce-order-actions {
.inside {
margin:0;
padding:0;
ul.order_actions {
li {
padding:6px 10px;
.total {
font-size: 1em !important;
width: 10em;
margin: 0 0 0 .5em;
-webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
-moz-box-sizing: border-box; /* Firefox, other Gecko */
box-sizing: border-box; /* Opera/IE 8+ */
&:last-child {
border-bottom:0;
}
}
}
}
}
#poststuff #woocommerce-order-totals {
.inside {
margin:0;
padding:0;
}
h4 {
margin:0 !important;
a.add_tax_row, a.add_total_row {
display: inline-block;
padding-bottom: 10px;
}
.inline_total {
input[type="text"] {
width: 96%;
float: right;
}
}
.refunded-total {
color: @red;
}
}
.refund-actions {
margin-top: 5px;
padding-top: 12px;
border-top: 1px solid #DFDFDF;
.button {
float: right;
margin-left: 4px;
}
.cancel-action {
float: left;
margin-left: 0;
}
}
.add_meta {
margin-left: 0 !important;
}
h3 small {
color: #999;
}
}
.totals_group {
border-top: 1px solid white;
border-bottom: 1px solid #DDD;
padding: 10px 12px 0 12px;
&:first-child {
border-top:0;
}
input, select {
width: 100%;
vertical-align: top;
margin: 0;
font-weight: normal;
line-height: 1em;
}
select {
height: 30px !important;
}
input {
padding: 4px 6px;
}
::-webkit-input-placeholder { line-height: 1.4em; }
::-moz-placeholder { line-height: 1.4em; } /* firefox 19+ */
:-ms-input-placeholder { line-height: 1.4em; } /* ie */
input:-moz-placeholder { line-height: 1.4em; }
#_order_total, #_order_discount {
margin: 6px 0 10px;
}
}
.buttons {
border-top: 1px solid white;
padding: 1em 10px 1em 10px;
margin: 0;
text-align: right;
.calc_line_taxes {
float: left;
}
}
ul.totals {
margin: 6px 0 0;
float: left;
li {
float: left;
clear: both;
width: 100%;
font-size: 1.2em;
font-weight: bold;
line-height: 1.2em;
margin: 0;
padding: 0 0 10px;
label {
font-weight: normal;
display: block;
font-size: 0.8em;
color: #333;
}
}
li.left {
float: left;
width: 49%;
clear: left;
input {
width: 100%;
}
}
li.right {
float: right;
width: 49%;
clear: none;
input {
width: 100%;
}
}
li.wide {
float: left;
width: 100%;
clear: left;
input {
width: 100%;
}
}
.calculated {
border-color: #ae8ca2;
border-style: dotted;
}
}
.total_rows {
margin: 6px 0 0;
.total_row:first-child {
border-top:1px solid #dfdfdf;
}
.total_row:last-child {
margin-bottom:9px;
}
}
.total_row {
margin:0 -12px;
border-bottom:1px solid #DFDFDF;
background: #fff;
padding: 12px 12px 3px 12px;
background:#f8f8f8;
position: relative;
p {
margin:0 0 9px;
}
label {
color:#999;
display: block;
margin: 0 0 3px;
}
p.first {
float: left;
width: 49%;
clear: left;
input, select {
width: 100%;
}
}
p.last {
float: right;
width: 49%;
clear: none;
input, select {
width: 100%;
}
}
p.wide {
clear: both;
input, select {
width: 100%;
}
}
a.delete_tax_row, a.delete_total_row {
.ir;
display:none;
position: absolute;
top:-.5em;
right:-.5em;
font-size:1.4em;
&:before {
.icon( "\e013" );
color:white;
background-color: #000;
-webkit-border-radius:100%;
border-radius:100%;
box-shadow:0 1px 2px rgba(0,0,0,0.2);
}
&:hover:before {
background-color: @red;
}
}
&:hover, &:focus {
a.delete_tax_row, a.delete_total_row {
display: block;
}
}
}
}
#poststuff #woocommerce-order-notes {
.inside {
margin:0;
padding:0;
ul.order_notes {
li {
padding:0 10px;
}
}
.amount {
white-space: nowrap;
}
}
.woocommerce_order_items_wrapper {
@ -860,10 +706,16 @@ ul.wc_coupon_list_block {
width: 100%;
background: #fff;
thead th {
background: #f5f5f5;
background: #f8f8f8;
padding: 8px;
font-size: 11px;
text-align: left;
&:last-child {
padding-right: 12px;
}
&:first-child {
padding-left: 12px;
}
}
tbody th, td {
padding: 8px;
@ -882,9 +734,24 @@ ul.wc_coupon_list_block {
padding: 4px;
color: #555;
}
&:last-child {
padding-right: 12px;
}
&:first-child {
padding-left: 12px;
}
}
tbody tr:last-child td {
border-bottom:1px solid #dfdfdf;
}
tbody tr:first-child td {
border-top: 8px solid #f8f8f8;
}
tbody#order_line_items tr:first-child td {
border-top: none;
}
td.check-column {
padding: 8px;
padding: 8px 8px 8px 12px;
width: 1%;
}
.item {
@ -914,6 +781,29 @@ ul.wc_coupon_list_block {
vertical-align:middle;
font-size: 1em;
}
.split-input {
display: block;
background: #fff;
border: 1px solid #ddd;
box-shadow: inset 0 1px 2px rgba(0,0,0,.07);
margin: 1px;
width: 70px;
input {
width: 100%;
-webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
-moz-box-sizing: border-box; /* Firefox, other Gecko */
box-sizing: border-box; /* Opera/IE 8+ */
border: 0;
box-shadow: none;
margin: 0;
color: #555;
background: transparent;
}
input:last-child {
color: #bbb;
border-top: 1px dashed #ddd;
}
}
}
.quantity {
text-align: center;
@ -990,8 +880,165 @@ ul.wc_coupon_list_block {
}
}
tr.fee {
.thumb {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAARklEQVQYGWP8//8/AzGACV3Rnj17/oMwujiGQnQFMD7RChlBbsRmFcwkEO3i4sJImonIumGmg0xBFifaRKIVgj2DbAUuNgCfThpracSKqwAAAABJRU5ErkJggg==) no-repeat center;
.thumb div {
.ir();
font-size: 14px;
margin: 6px;
&:before {
.icon( "\e007" );
color: #bbbbbb;
}
}
}
tr.refund {
.thumb div {
.ir();
font-size: 14px;
margin: 6px;
&:before {
.icon( "\e014" );
color: #bbbbbb;
}
}
}
tr.shipping {
.thumb div {
.ir();
font-size: 14px;
margin: 6px;
&:before {
.icon( "\e01a" );
color: #bbbbbb;
}
}
}
th.line_tax {
white-space: nowrap;
}
th.line_tax, td.line_tax {
padding: 8px 16px 8px 8px;
.delete-order-tax {
.ir;
font-size: 12px;
visibility: hidden;
float: right;
margin: 2px -16px 0 0;
&:before {
.icon( "\e013" );
color:white;
background-color: #000;
-webkit-border-radius:100%;
border-radius:100%;
border: 1px solid #000;
box-shadow:0 1px 2px rgba(0,0,0,0.2);
}
&:hover:before {
border-color: @red;
background-color: @red;
}
}
&:hover {
.delete-order-tax {
visibility: visible;
}
}
}
small.refunded {
display: block;
color: @red;
white-space: nowrap;
}
}
}
.wc-order-items-editable {
.edit-order-item {
.ir;
display: inline-block;
margin: 0 .5em 0 0;
&:before {
.icon;
content: "\e603";
color: #999;
}
&:hover {
&:before {
color: #555;
}
}
}
.delete-order-item,
.delete_refund {
.ir;
display: inline-block;
margin: 0;
&:before {
.icon;
content: "\e013";
color: #999;
}
&:hover {
&:before {
color: @red;
}
}
}
.wc-order-edit-line-item-actions {
width: 2.5em;
text-align: right;
}
.wc-order-totals .wc-order-edit-line-item-actions {
width: 1.5em;
}
.wc-order-totals .edit-order-item {
margin: 0;
}
}
#woocommerce-order-downloads {
.buttons {
float:left;
padding: 0;
margin: 0;
vertical-align: top;
.add_item_id, .chosen-container {
width: 400px !important;
margin-right: 9px;
vertical-align: top;
float:left;
}
button {
margin: 2px 0 0 0;
}
}
h3 small {
color: #999;
}
}
#poststuff #woocommerce-order-actions {
.inside {
margin:0;
padding:0;
ul.order_actions {
li {
padding:6px 10px;
-webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */
-moz-box-sizing: border-box; /* Firefox, other Gecko */
box-sizing: border-box; /* Opera/IE 8+ */
&:last-child {
border-bottom:0;
}
}
}
}
}
#poststuff #woocommerce-order-notes {
.inside {
margin:0;
padding:0;
ul.order_notes {
li {
padding:0 10px;
}
}
}
@ -3282,3 +3329,87 @@ table.bar_chart {
top: 8px;
}
}
/* Backbone modal dialog
----------------------------------*/
.wc-backbone-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 160000;
* {
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
}
.wc-backbone-modal-content {
position: absolute;
top: 50%;
left: 50%;
width: 500px;
background: #fff;
margin: -150px 0 0 -250px;
}
}
.wc-backbone-modal-backdrop {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
min-height: 360px;
background: #000;
opacity: .7;
z-index: 159900;
}
.wc-backbone-modal-main {
padding-bottom: 50px;
header,
article {
display: block;
position: relative;
padding: 4px 16px;
}
header {
border-bottom: 1px solid #ddd;
}
article {
padding: 10px 16px;
.pagination {
padding: 10px 0 0;
text-align: center;
}
}
h1 {
font-size: 22px;
font-weight: 200;
line-height: 45px;
margin: 0;
}
footer {
position: absolute;
left: 0;
right: 0;
bottom: 0;
height: 30px;
z-index: 100;
padding: 10px 0px;
border: 0 solid #dfdfdf;
border-width: 1px 0 0 0;
box-shadow: 0 -4px 4px -4px rgba(0,0,0,0.1);
}
footer .inner {
padding: 0 10px;
text-align: right;
}
}

View File

@ -0,0 +1,17 @@
jQuery( function($){
// Coupon type options
$('select#discount_type').change(function(){
// Get value
var select_val = $(this).val();
if ( select_val == 'fixed_product' || select_val == 'percent_product' ) {
$('.limit_usage_to_x_items_field').show();
} else {
$('.limit_usage_to_x_items_field').hide();
}
}).change();
});

View File

@ -0,0 +1 @@
jQuery(function(a){a("select#discount_type").change(function(){var b=a(this).val();"fixed_product"==b||"percent_product"==b?a(".limit_usage_to_x_items_field").show():a(".limit_usage_to_x_items_field").hide()}).change()});

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,649 @@
jQuery( function($){
// Scroll to first checked category - https://github.com/scribu/wp-category-checklist-tree/blob/d1c3c1f449e1144542efa17dde84a9f52ade1739/category-checklist-tree.php
$(function(){
$('[id$="-all"] > ul.categorychecklist').each(function() {
var $list = $(this);
var $firstChecked = $list.find(':checked').first();
if ( !$firstChecked.length )
return;
var pos_first = $list.find('input').position().top;
var pos_checked = $firstChecked.position().top;
$list.closest('.tabs-panel').scrollTop(pos_checked - pos_first + 5);
});
});
// Prevent enter submitting post form
$("#upsell_product_data").bind("keypress", function(e) {
if (e.keyCode == 13) return false;
});
// Type box
$('.type_box').appendTo( '#woocommerce-product-data h3.hndle span' );
$(function(){
// Prevent inputs in meta box headings opening/closing contents
$('#woocommerce-product-data h3.hndle').unbind('click.postboxes');
jQuery('#woocommerce-product-data').on('click', 'h3.hndle', function(event){
// If the user clicks on some form input inside the h3 the box should not be toggled
if ( $(event.target).filter('input, option, label, select').length )
return;
$('#woocommerce-product-data').toggleClass('closed');
});
});
// Catalog Visibility
$('#catalog-visibility .edit-catalog-visibility').click(function () {
if ($('#catalog-visibility-select').is(":hidden")) {
$('#catalog-visibility-select').slideDown('fast');
$(this).hide();
}
return false;
});
$('#catalog-visibility .save-post-visibility').click(function () {
$('#catalog-visibility-select').slideUp('fast');
$('#catalog-visibility .edit-catalog-visibility').show();
var value = $('input[name=_visibility]:checked').val();
var label = $('input[name=_visibility]:checked').attr('data-label');
if ( $('input[name=_featured]').is(':checked') ) {
label = label + ', ' + woocommerce_admin_meta_boxes.featured_label
$('input[name=_featured]').attr('checked', 'checked');
}
$('#catalog-visibility-display').text( label );
return false;
});
$('#catalog-visibility .cancel-post-visibility').click(function () {
$('#catalog-visibility-select').slideUp('fast');
$('#catalog-visibility .edit-catalog-visibility').show();
var current_visibility = $('#current_visibility').val();
var current_featured = $('#current_featured').val();
$('input[name=_visibility]').removeAttr('checked');
$('input[name=_visibility][value=' + current_visibility + ']').attr('checked', 'checked');
var label = $('input[name=_visibility]:checked').attr('data-label');
if ( current_featured == 'yes' ) {
label = label + ', ' + woocommerce_admin_meta_boxes.featured_label
$('input[name=_featured]').attr('checked', 'checked');
} else {
$('input[name=_featured]').removeAttr('checked');
}
$('#catalog-visibility-display').text( label );
return false;
});
// PRODUCT TYPE SPECIFIC OPTIONS
$('select#product-type').change(function(){
// Get value
var select_val = $(this).val();
if (select_val=='variable') {
$('input#_manage_stock').change();
$('input#_downloadable').prop('checked', false);
$('input#_virtual').removeAttr('checked');
}
else if (select_val=='grouped') {
$('input#_downloadable').prop('checked', false);
$('input#_virtual').removeAttr('checked');
}
else if (select_val=='external') {
$('input#_downloadable').prop('checked', false);
$('input#_virtual').removeAttr('checked');
}
show_and_hide_panels();
$('ul.wc-tabs li:visible').eq(0).find('a').click();
$('body').trigger('woocommerce-product-type-change', select_val, $(this) );
}).change();
$('input#_downloadable, input#_virtual').change(function(){
show_and_hide_panels();
});
function show_and_hide_panels() {
var product_type = $('select#product-type').val();
var is_virtual = $('input#_virtual:checked').size();
var is_downloadable = $('input#_downloadable:checked').size();
// Hide/Show all with rules
var hide_classes = '.hide_if_downloadable, .hide_if_virtual';
var show_classes = '.show_if_downloadable, .show_if_virtual, .show_if_external';
$.each( woocommerce_admin_meta_boxes.product_types, function( index, value ) {
hide_classes = hide_classes + ', .hide_if_' + value;
show_classes = show_classes + ', .show_if_' + value;
} );
$( hide_classes ).show();
$( show_classes ).hide();
// Shows rules
if ( is_downloadable ) {
$('.show_if_downloadable').show();
}
if ( is_virtual ) {
$('.show_if_virtual').show();
}
$('.show_if_' + product_type).show();
// Hide rules
if ( is_downloadable ) {
$('.hide_if_downloadable').hide();
}
if ( is_virtual ) {
$('.hide_if_virtual').hide();
}
$('.hide_if_' + product_type).hide();
$('input#_manage_stock').change();
}
// Sale price schedule
$('.sale_price_dates_fields').each(function() {
var $these_sale_dates = $(this);
var sale_schedule_set = false;
var $wrap = $these_sale_dates.closest( 'div, table' );
$these_sale_dates.find('input').each(function(){
if ( $(this).val() != '' )
sale_schedule_set = true;
});
if ( sale_schedule_set ) {
$wrap.find('.sale_schedule').hide();
$wrap.find('.sale_price_dates_fields').show();
} else {
$wrap.find('.sale_schedule').show();
$wrap.find('.sale_price_dates_fields').hide();
}
});
$('#woocommerce-product-data').on( 'click', '.sale_schedule', function() {
var $wrap = $(this).closest( 'div, table' );
$(this).hide();
$wrap.find('.cancel_sale_schedule').show();
$wrap.find('.sale_price_dates_fields').show();
return false;
});
$('#woocommerce-product-data').on( 'click', '.cancel_sale_schedule', function() {
var $wrap = $(this).closest( 'div, table' );
$(this).hide();
$wrap.find('.sale_schedule').show();
$wrap.find('.sale_price_dates_fields').hide();
$wrap.find('.sale_price_dates_fields').find('input').val('');
return false;
});
// File inputs
$('#woocommerce-product-data').on('click','.downloadable_files a.insert',function(){
$(this).closest('.downloadable_files').find('tbody').append( $(this).data( 'row' ) );
return false;
});
$('#woocommerce-product-data').on('click','.downloadable_files a.delete',function(){
$(this).closest('tr').remove();
return false;
});
// STOCK OPTIONS
$('input#_manage_stock').change(function(){
if ( $(this).is(':checked') ) {
$('div.stock_fields').show();
} else {
$('div.stock_fields').hide();
}
}).change();
// DATE PICKER FIELDS
var dates = $( ".sale_price_dates_fields input" ).datepicker({
defaultDate: "",
dateFormat: "yy-mm-dd",
numberOfMonths: 1,
showButtonPanel: true,
showOn: "button",
buttonImage: woocommerce_admin_meta_boxes.calendar_image,
buttonImageOnly: true,
onSelect: function( selectedDate ) {
var option = $(this).is('#_sale_price_dates_from, .sale_price_dates_from') ? "minDate" : "maxDate";
var instance = $( this ).data( "datepicker" ),
date = $.datepicker.parseDate(
instance.settings.dateFormat ||
$.datepicker._defaults.dateFormat,
selectedDate, instance.settings );
dates.not( this ).datepicker( "option", option, date );
}
});
// ATTRIBUTE TABLES
// Multiselect attributes
$(".product_attributes select.multiselect").chosen();
// Initial order
var woocommerce_attribute_items = $('.product_attributes').find('.woocommerce_attribute').get();
woocommerce_attribute_items.sort(function(a, b) {
var compA = parseInt($(a).attr('rel'));
var compB = parseInt($(b).attr('rel'));
return (compA < compB) ? -1 : (compA > compB) ? 1 : 0;
})
$(woocommerce_attribute_items).each( function(idx, itm) { $('.product_attributes').append(itm); } );
function attribute_row_indexes() {
$('.product_attributes .woocommerce_attribute').each(function(index, el){
$('.attribute_position', el).val( parseInt( $(el).index('.product_attributes .woocommerce_attribute') ) );
});
};
// Add rows
$('button.add_attribute').on('click', function(){
var size = $('.product_attributes .woocommerce_attribute').size();
var attribute_type = $('select.attribute_taxonomy').val();
if (!attribute_type) {
var product_type = $('select#product-type').val();
if (product_type!='variable') enable_variation = 'style="display:none;"'; else enable_variation = '';
// Add custom attribute row
$('.product_attributes').append('<div class="woocommerce_attribute wc-metabox">\
<h3>\
<button type="button" class="remove_row button">' + woocommerce_admin_meta_boxes.remove_label + '</button>\
<div class="handlediv" title="' + woocommerce_admin_meta_boxes.click_to_toggle + '"></div>\
<strong class="attribute_name"></strong>\
</h3>\
<table cellpadding="0" cellspacing="0" class="woocommerce_attribute_data">\
<tbody>\
<tr>\
<td class="attribute_name">\
<label>' + woocommerce_admin_meta_boxes.name_label + ':</label>\
<input type="text" class="attribute_name" name="attribute_names[' + size + ']" />\
<input type="hidden" name="attribute_is_taxonomy[' + size + ']" value="0" />\
<input type="hidden" name="attribute_position[' + size + ']" class="attribute_position" value="' + size + '" />\
</td>\
<td rowspan="3">\
<label>' + woocommerce_admin_meta_boxes.values_label + ':</label>\
<textarea name="attribute_values[' + size + ']" cols="5" rows="5" placeholder="' + woocommerce_admin_meta_boxes.text_attribute_tip + '"></textarea>\
</td>\
</tr>\
<tr>\
<td>\
<label><input type="checkbox" class="checkbox" ' + ( woocommerce_admin_meta_boxes.default_attribute_visibility ? 'checked="checked"' : '' ) + ' name="attribute_visibility[' + size + ']" value="1" /> ' + woocommerce_admin_meta_boxes.visible_label + '</label>\
</td>\
</tr>\
<tr>\
<td>\
<div class="enable_variation show_if_variable" ' + enable_variation + '>\
<label><input type="checkbox" class="checkbox" ' + ( woocommerce_admin_meta_boxes.default_attribute_variation ? 'checked="checked"' : '' ) + ' name="attribute_variation[' + size + ']" value="1" /> ' + woocommerce_admin_meta_boxes.used_for_variations_label + '</label>\
</div>\
</td>\
</tr>\
</tbody>\
</table>\
</div>');
} else {
// Reveal taxonomy row
var thisrow = $('.product_attributes .woocommerce_attribute.' + attribute_type);
$('.product_attributes').append( $(thisrow) );
$(thisrow).show().find('.woocommerce_attribute_data').show();
attribute_row_indexes();
}
$('select.attribute_taxonomy').val('');
});
$('.product_attributes').on('blur', 'input.attribute_name', function(){
$(this).closest('.woocommerce_attribute').find('strong.attribute_name').text( $(this).val() );
});
$('.product_attributes').on('click', 'button.select_all_attributes', function(){
$(this).closest('td').find('select option').attr("selected","selected");
$(this).closest('td').find('select').trigger("chosen:updated");
return false;
});
$('.product_attributes').on('click', 'button.select_no_attributes', function(){
$(this).closest('td').find('select option').removeAttr("selected");
$(this).closest('td').find('select').trigger("chosen:updated");
return false;
});
$('.product_attributes').on('click', 'button.remove_row', function() {
var answer = confirm(woocommerce_admin_meta_boxes.remove_attribute);
if (answer){
var $parent = $(this).parent().parent();
if ($parent.is('.taxonomy')) {
$parent.find('select, input[type=text]').val('');
$parent.hide();
} else {
$parent.find('select, input[type=text]').val('');
$parent.hide();
attribute_row_indexes();
}
}
return false;
});
// Attribute ordering
$('.product_attributes').sortable({
items:'.woocommerce_attribute',
cursor:'move',
axis:'y',
handle: 'h3',
scrollSensitivity:40,
forcePlaceholderSize: true,
helper: 'clone',
opacity: 0.65,
placeholder: 'wc-metabox-sortable-placeholder',
start:function(event,ui){
ui.item.css('background-color','#f6f6f6');
},
stop:function(event,ui){
ui.item.removeAttr('style');
attribute_row_indexes();
}
});
// Add a new attribute (via ajax)
$('.product_attributes').on('click', 'button.add_new_attribute', function() {
$('.product_attributes').block({ message: null, overlayCSS: { background: '#fff url(' + woocommerce_admin_meta_boxes.plugin_url + '/assets/images/ajax-loader.gif) no-repeat center', opacity: 0.6 } });
var attribute = $(this).attr('data-attribute');
var $wrapper = $(this).closest('.woocommerce_attribute_data');
var new_attribute_name = prompt( woocommerce_admin_meta_boxes.new_attribute_prompt );
if ( new_attribute_name ) {
var data = {
action: 'woocommerce_add_new_attribute',
taxonomy: attribute,
term: new_attribute_name,
security: woocommerce_admin_meta_boxes.add_attribute_nonce
};
$.post( woocommerce_admin_meta_boxes.ajax_url, data, function( response ) {
if ( response.error ) {
// Error
alert( response.error );
} else if ( response.slug ) {
// Success
$wrapper.find('select.attribute_values').append('<option value="' + response.slug + '" selected="selected">' + response.name + '</option>');
$wrapper.find('select.attribute_values').trigger("chosen:updated");
}
$('.product_attributes').unblock();
});
} else {
$('.product_attributes').unblock();
}
return false;
});
// Save attributes and update variations
$('.save_attributes').on('click', function(){
$('.product_attributes').block({ message: null, overlayCSS: { background: '#fff url(' + woocommerce_admin_meta_boxes.plugin_url + '/assets/images/ajax-loader.gif) no-repeat center', opacity: 0.6 } });
var data = {
post_id: woocommerce_admin_meta_boxes.post_id,
data: $('.product_attributes').find('input, select, textarea').serialize(),
action: 'woocommerce_save_attributes',
security: woocommerce_admin_meta_boxes.save_attributes_nonce
};
$.post( woocommerce_admin_meta_boxes.ajax_url, data, function( response ) {
var this_page = window.location.toString();
this_page = this_page.replace( 'post-new.php?', 'post.php?post=' + woocommerce_admin_meta_boxes.post_id + '&action=edit&' );
// Load variations panel
$('#variable_product_options').block({ message: null, overlayCSS: { background: '#fff url(' + woocommerce_admin_meta_boxes.plugin_url + '/assets/images/ajax-loader.gif) no-repeat center', opacity: 0.6 } });
$('#variable_product_options').load( this_page + ' #variable_product_options_inner', function() {
$('#variable_product_options').unblock();
} );
$('.product_attributes').unblock();
});
});
// Uploading files
var downloadable_file_frame;
var file_path_field;
jQuery(document).on( 'click', '.upload_file_button', function( event ){
var $el = $(this);
file_path_field = $el.closest('tr').find('td.file_url input');
event.preventDefault();
// If the media frame already exists, reopen it.
if ( downloadable_file_frame ) {
downloadable_file_frame.open();
return;
}
var downloadable_file_states = [
// Main states.
new wp.media.controller.Library({
library: wp.media.query(),
multiple: true,
title: $el.data('choose'),
priority: 20,
filterable: 'uploaded',
})
];
// Create the media frame.
downloadable_file_frame = wp.media.frames.downloadable_file = wp.media({
// Set the title of the modal.
title: $el.data('choose'),
library: {
type: ''
},
button: {
text: $el.data('update'),
},
multiple: true,
states: downloadable_file_states,
});
// When an image is selected, run a callback.
downloadable_file_frame.on( 'select', function() {
var file_path = '';
var selection = downloadable_file_frame.state().get('selection');
selection.map( function( attachment ) {
attachment = attachment.toJSON();
if ( attachment.url )
file_path = attachment.url
} );
file_path_field.val( file_path );
});
// Set post to 0 and set our custom type
downloadable_file_frame.on( 'ready', function() {
downloadable_file_frame.uploader.options.uploader.params = {
type: 'downloadable_product'
};
});
// Finally, open the modal.
downloadable_file_frame.open();
});
// Download ordering
jQuery('.downloadable_files tbody').sortable({
items:'tr',
cursor:'move',
axis:'y',
handle: 'td.sort',
scrollSensitivity:40,
forcePlaceholderSize: true,
helper: 'clone',
opacity: 0.65,
});
// Product gallery file uploads
var product_gallery_frame;
var $image_gallery_ids = $('#product_image_gallery');
var $product_images = $('#product_images_container ul.product_images');
jQuery('.add_product_images').on( 'click', 'a', function( event ) {
var $el = $(this);
var attachment_ids = $image_gallery_ids.val();
event.preventDefault();
// If the media frame already exists, reopen it.
if ( product_gallery_frame ) {
product_gallery_frame.open();
return;
}
// Create the media frame.
product_gallery_frame = wp.media.frames.product_gallery = wp.media({
// Set the title of the modal.
title: $el.data('choose'),
button: {
text: $el.data('update'),
},
states : [
new wp.media.controller.Library({
title: $el.data('choose'),
filterable : 'all',
multiple: true,
})
]
});
// When an image is selected, run a callback.
product_gallery_frame.on( 'select', function() {
var selection = product_gallery_frame.state().get('selection');
selection.map( function( attachment ) {
attachment = attachment.toJSON();
if ( attachment.id ) {
attachment_ids = attachment_ids ? attachment_ids + "," + attachment.id : attachment.id;
$product_images.append('\
<li class="image" data-attachment_id="' + attachment.id + '">\
<img src="' + attachment.url + '" />\
<ul class="actions">\
<li><a href="#" class="delete" title="' + $el.data('delete') + '">' + $el.data('text') + '</a></li>\
</ul>\
</li>');
}
});
$image_gallery_ids.val( attachment_ids );
});
// Finally, open the modal.
product_gallery_frame.open();
});
// Image ordering
$product_images.sortable({
items: 'li.image',
cursor: 'move',
scrollSensitivity:40,
forcePlaceholderSize: true,
forceHelperSize: false,
helper: 'clone',
opacity: 0.65,
placeholder: 'wc-metabox-sortable-placeholder',
start:function(event,ui){
ui.item.css('background-color','#f6f6f6');
},
stop:function(event,ui){
ui.item.removeAttr('style');
},
update: function(event, ui) {
var attachment_ids = '';
$('#product_images_container ul li.image').css('cursor','default').each(function() {
var attachment_id = jQuery(this).attr( 'data-attachment_id' );
attachment_ids = attachment_ids + attachment_id + ',';
});
$image_gallery_ids.val( attachment_ids );
}
});
// Remove images
$('#product_images_container').on( 'click', 'a.delete', function() {
$(this).closest('li.image').remove();
var attachment_ids = '';
$('#product_images_container ul li.image').css('cursor','default').each(function() {
var attachment_id = jQuery(this).attr( 'data-attachment_id' );
attachment_ids = attachment_ids + attachment_id + ',';
});
$image_gallery_ids.val( attachment_ids );
runTipTip();
return false;
});
});

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,124 @@
/*global jQuery, Backbone, _ */
( function ( $, Backbone, _ ) {
'use strict';
/**
* WooCommerce Backbone Modal plugin
*
* @param {object} options
*/
$.fn.WCBackboneModal = function( options ) {
return this.each( function () {
( new $.WCBackboneModal( $( this ), options ) );
});
};
/**
* Initialize the Backbone Modal
*
* @param {object} element [description]
* @param {object} options [description]
*/
$.WCBackboneModal = function( element, options ) {
// Set settings
var settings = $.extend( {}, $.WCBackboneModal.defaultOptions, options );
if ( settings.template ) {
new $.WCBackboneModal.View({
target: settings.template
});
}
};
/**
* Set default options
*
* @type {object}
*/
$.WCBackboneModal.defaultOptions = {
template: '',
};
/**
* Create the Backbone Modal
*
* @return {null}
*/
$.WCBackboneModal.View = Backbone.View.extend({
tagName: 'div',
id: 'wc-backbone-modal-dialog',
_target: undefined,
events: {
'click #btn-cancel': 'closeButton',
'click #btn-ok': 'addButton',
},
initialize: function ( data ) {
this._target = data.target;
_.bindAll( this, 'render' );
this.render();
},
render: function () {
this.$el.attr( 'tabindex' , '0' ).append( $( this._target ).html() );
$( 'body' ).css({
'overflow': 'hidden'
}).append( this.$el );
var $content = $( '.wc-backbone-modal-content' ).find( 'article' );
var content_h = $content.height();
var max_h = $( window ).height() - 200;
if ( max_h > 400 ) {
max_h = 400;
}
if ( content_h > max_h ) {
$content.css({
'overflow': 'auto',
height: max_h + 'px'
});
} else {
$content.css({
'overflow': 'visible',
height: content_h
});
}
$( '.wc-backbone-modal-content' ).css({
'margin-top': '-' + ( $( '.wc-backbone-modal-content' ).height() / 2 ) + 'px'
});
$( 'body' ).trigger( 'wc_backbone_modal_loaded', this._target );
},
closeButton: function ( e ) {
e.preventDefault();
this.undelegateEvents();
$( document ).off( 'focusin' );
$( 'body' ).css({
'overflow': 'auto'
});
this.remove();
$( 'body' ).trigger( 'wc_backbone_modal_removed', this._target );
},
addButton: function ( e ) {
$( 'body' ).trigger( 'wc_backbone_modal_response', this._target, this.getFormData() );
this.closeButton( e );
},
getFormData: function () {
var data = {};
$.each( $( 'form', this.$el ).serializeArray(), function( index, item ) {
if ( data.hasOwnProperty( item.name ) ) {
data[ item.name ] = $.makeArray( data[ item.name ] );
data[ item.name ].push( item.value );
}
else {
data[ item.name ] = item.value;
}
});
return data;
}
});
}( jQuery, Backbone, _ ));

View File

@ -0,0 +1 @@
!function(a,b,c){"use strict";a.fn.WCBackboneModal=function(b){return this.each(function(){new a.WCBackboneModal(a(this),b)})},a.WCBackboneModal=function(b,c){var d=a.extend({},a.WCBackboneModal.defaultOptions,c);d.template&&new a.WCBackboneModal.View({target:d.template})},a.WCBackboneModal.defaultOptions={template:""},a.WCBackboneModal.View=b.View.extend({tagName:"div",id:"wc-backbone-modal-dialog",_target:void 0,events:{"click #btn-cancel":"closeButton","click #btn-ok":"addButton"},initialize:function(a){this._target=a.target,c.bindAll(this,"render"),this.render()},render:function(){this.$el.attr("tabindex","0").append(a(this._target).html()),a("body").css({overflow:"hidden"}).append(this.$el);var b=a(".wc-backbone-modal-content").find("article"),c=b.height(),d=a(window).height()-200;d>400&&(d=400),b.css(c>d?{overflow:"auto",height:d+"px"}:{overflow:"visible",height:c}),a(".wc-backbone-modal-content").css({"margin-top":"-"+a(".wc-backbone-modal-content").height()/2+"px"}),a("body").trigger("wc_backbone_modal_loaded",this._target)},closeButton:function(b){b.preventDefault(),this.undelegateEvents(),a(document).off("focusin"),a("body").css({overflow:"auto"}),this.remove(),a("body").trigger("wc_backbone_modal_removed",this._target)},addButton:function(b){a("body").trigger("wc_backbone_modal_response",this._target,this.getFormData()),this.closeButton(b)},getFormData:function(){var b={};return a.each(a("form",this.$el).serializeArray(),function(c,d){b.hasOwnProperty(d.name)?(b[d.name]=a.makeArray(b[d.name]),b[d.name].push(d.value)):b[d.name]=d.value}),b}})}(jQuery,Backbone,_);

View File

@ -125,10 +125,23 @@ abstract class WC_Abstract_Order {
wc_add_order_item_meta( $item_id, '_line_subtotal_tax', wc_format_decimal( isset( $args['totals']['subtotal_tax'] ) ? $args['totals']['subtotal_tax'] : 0 ) );
wc_add_order_item_meta( $item_id, '_line_tax', wc_format_decimal( isset( $args['totals']['tax'] ) ? $args['totals']['tax'] : 0 ) );
// Save tax data - Since 2.2
if ( isset( $args['totals']['tax_data'] ) ) {
$tax_data = array();
$tax_data['total'] = array_map( 'wc_format_decimal', $args['totals']['tax_data']['total'] );
$tax_data['subtotal'] = array_map( 'wc_format_decimal', $args['totals']['tax_data']['subtotal'] );
wc_add_order_item_meta( $item_id, '_line_tax_data', $tax_data );
} else {
wc_add_order_item_meta( $item_id, '_line_tax_data', array( 'total' => array(), 'subtotal' => array() ) );
}
// Add variation meta
if ( ! empty( $args['variation'] ) ) {
foreach ( $args['variation'] as $key => $value ) {
wc_add_order_item_meta( $item_id, str_replace( 'attribute_', '', $key ), $value );
}
}
// Backorders
if ( $product->backorders_require_notification() && $product->is_on_backorder( $qty ) ) {
@ -302,6 +315,10 @@ abstract class WC_Abstract_Order {
wc_add_order_item_meta( $item_id, 'method_id', $shipping_rate->id );
wc_add_order_item_meta( $item_id, 'cost', wc_format_decimal( $shipping_rate->cost ) );
// Save shipping taxes - Since 2.2
$taxes = array_map( 'wc_format_decimal', $shipping_rate->taxes );
wc_add_order_item_meta( $item_id, 'taxes', $taxes );
do_action( 'woocommerce_order_add_shipping', $this->id, $item_id, $shipping_rate );
// Update total
@ -370,6 +387,10 @@ abstract class WC_Abstract_Order {
wc_add_order_item_meta( $item_id, '_line_total', wc_format_decimal( $fee->amount ) );
wc_add_order_item_meta( $item_id, '_line_tax', wc_format_decimal( $fee->tax ) );
// Save tax data - Since 2.2
$tax_data = array_map( 'wc_format_decimal', $fee->tax_data );
wc_add_order_item_meta( $item_id, '_line_tax_data', array( 'total' => $tax_data ) );
do_action( 'woocommerce_order_add_fee', $this->id, $item_id, $fee );
return $item_id;
@ -566,18 +587,68 @@ abstract class WC_Abstract_Order {
return $this->get_total_shipping();
}
/**
* Update tax lines at order level by looking at the line item taxes themselves.
*
* @return bool success or fail
*/
public function update_taxes() {
$order_taxes = array();
$order_shipping_taxes = array();
foreach ( $this->get_items( array( 'line_item', 'fee' ) ) as $item_id => $item ) {
$line_tax_data = maybe_unserialize( $item['line_tax_data'] );
if ( isset( $line_tax_data['total'] ) ) {
foreach ( $line_tax_data['total'] as $tax_rate_id => $tax ) {
if ( ! isset( $order_taxes[ $tax_rate_id ] ) ) {
$order_taxes[ $tax_rate_id ] = 0;
}
$order_taxes[ $tax_rate_id ] += $tax;
}
}
}
foreach ( $this->get_items( array( 'shipping' ) ) as $item_id => $item ) {
$line_tax_data = maybe_unserialize( $item['taxes'] );
if ( isset( $line_tax_data['total'] ) ) {
foreach ( $line_tax_data['total'] as $tax_rate_id => $tax ) {
if ( ! isset( $order_shipping_taxes[ $tax_rate_id ] ) ) {
$order_shipping_taxes[ $tax_rate_id ] = 0;
}
$order_shipping_taxes[ $tax_rate_id ] += $tax;
}
}
}
// Remove old existing tax rows
$this->remove_order_items( 'tax' );
// Now merge to keep tax rows
foreach ( array_keys( $order_taxes + $order_shipping_taxes ) as $tax_rate_id ) {
$this->add_tax( $tax_rate_id, isset( $order_taxes[ $tax_rate_id ] ) ? $order_taxes[ $tax_rate_id ] : 0, isset( $order_shipping_taxes[ $tax_rate_id ] ) ? $order_shipping_taxes[ $tax_rate_id ] : 0 );
}
// Save tax totals
$this->set_total( WC_Tax::round( array_sum( $order_shipping_taxes ) ), 'shipping_tax' );
$this->set_total( WC_Tax::round( array_sum( $order_taxes ) ), 'tax' );
return true;
}
/**
* Calculate totals by looking at the contents of the order. Stores the totals and returns the orders final total.
*
* @since 2.2
* @param $and_taxes bool Calc taxes if true
* @return float calculated grand total
*/
public function calculate_totals() {
public function calculate_totals( $and_taxes = true ) {
$cart_subtotal = 0;
$cart_total = 0;
$fee_total = 0;
if ( $and_taxes ) {
$this->calculate_taxes();
}
// line items
foreach ( $this->get_items() as $item ) {
@ -713,6 +784,14 @@ abstract class WC_Abstract_Order {
return $this->get_user_id() ? get_user_by( 'id', $this->get_user_id() ) : false;
}
/**
* Get transaction id for the order
* @return string
*/
public function get_transaction_id() {
return get_post_meta( $this->id, '_transaction_id', true );
}
/**
* Check if an order key is valid.
*
@ -1513,8 +1592,10 @@ abstract class WC_Abstract_Order {
public function get_product_from_item( $item ) {
if ( ! empty( $item['variation_id'] ) && 'product_variation' === get_post_type( $item['variation_id'] ) ) {
$_product = get_product( $item['variation_id'] );
} else {
} elseif ( ! empty( $item['product_id'] ) ) {
$_product = get_product( $item['product_id'] );
} else {
$_product = false;
}
return apply_filters( 'woocommerce_get_product_from_item', $_product, $item, $this );
}
@ -2032,7 +2113,7 @@ abstract class WC_Abstract_Order {
add_post_meta( $this->id, '_paid_date', current_time('mysql'), true );
if ( ! empty( $transaction_id ) ) {
add_post_meta( $this->id, '_transaction_id', $transaction_id );
add_post_meta( $this->id, '_transaction_id', $transaction_id, true );
}
$this_order = array(

View File

@ -46,7 +46,7 @@ abstract class WC_Payment_Gateway extends WC_Settings_API {
/** @var string Description for the gateway. */
public $description;
/** @var array Array of supported features such as 'default_credit_card_form' */
/** @var array Array of supported features such as 'default_credit_card_form', 'refunds' */
public $supports = array( 'products' );
/** @var int Maximum transaction amount, zero does not define a maximum */
@ -185,13 +185,34 @@ abstract class WC_Payment_Gateway extends WC_Settings_API {
/**
* Process Payment
*
* Process the payment. Override this in your gateway.
* Process the payment. Override this in your gateway. When implemented, this should
* return the success and redirect in an array. e.g.
*
* return array(
* 'result' => 'success',
* 'redirect' => $this->get_return_url( $order )
* );
*
* @param int $order_id
* @access public
* @return void
* @return array
*/
public function process_payment( $order_id ) {}
public function process_payment( $order_id ) {
return array();
}
/**
* Process Refund
*
* If the gateway declares 'refunds' support, this will allow it to refund
* a passed in amount.
*
* @param int $order_id
* @param float $amount
* @return bool|wp_error True or false based on success, or a WP_Error object
*/
public function process_refund( $order_id, $amount = null ) {
return false;
}
/**
* Validate Frontend Fields

View File

@ -447,7 +447,7 @@ class WC_Product {
* @return string
*/
public function get_title() {
return apply_filters( 'woocommerce_product_title', $this->post->post_title, $this );
return apply_filters( 'woocommerce_product_title', $this->post ? $this->post->post_title : '', $this );
}
/**

View File

@ -76,9 +76,7 @@ class WC_Admin_Assets {
wp_register_script( 'round', WC()->plugin_url() . '/assets/js/admin/round' . $suffix . '.js', array( 'jquery' ), WC_VERSION );
wp_register_script( 'woocommerce_admin_meta_boxes', WC()->plugin_url() . '/assets/js/admin/meta-boxes' . $suffix . '.js', array( 'jquery', 'jquery-ui-datepicker', 'jquery-ui-sortable', 'accounting', 'round' ), WC_VERSION );
wp_register_script( 'woocommerce_admin_meta_boxes_variations', WC()->plugin_url() . '/assets/js/admin/meta-boxes-variations' . $suffix . '.js', array( 'jquery', 'jquery-ui-sortable' ), WC_VERSION );
wp_register_script( 'wc-admin-meta-boxes', WC()->plugin_url() . '/assets/js/admin/meta-boxes' . $suffix . '.js', array( 'jquery', 'jquery-ui-datepicker', 'jquery-ui-sortable', 'accounting', 'round', 'ajax-chosen', 'chosen', 'plupload-all' ), WC_VERSION );
wp_register_script( 'ajax-chosen', WC()->plugin_url() . '/assets/js/chosen/ajax-chosen.jquery' . $suffix . '.js', array('jquery', 'chosen'), WC_VERSION );
@ -116,26 +114,59 @@ class WC_Admin_Assets {
}
// Edit product category pages
if ( in_array( $screen->id, array( 'edit-product_cat' ) ) )
if ( in_array( $screen->id, array( 'edit-product_cat' ) ) ) {
wp_enqueue_media();
}
// Products
if ( in_array( $screen->id, array( 'edit-product' ) ) )
if ( in_array( $screen->id, array( 'edit-product' ) ) ) {
wp_enqueue_script( 'woocommerce_quick-edit', WC()->plugin_url() . '/assets/js/admin/quick-edit' . $suffix . '.js', array('jquery'), WC_VERSION );
}
// Product/Coupon/Orders
if ( in_array( $screen->id, array( 'shop_coupon', 'shop_order', 'product', 'edit-shop_coupon', 'edit-shop_order', 'edit-product' ) ) ) {
wp_enqueue_script( 'woocommerce_admin_meta_boxes' );
wp_enqueue_script( 'jquery-ui-datepicker' );
// Meta boxes
if ( in_array( $screen->id, array( 'product', 'edit-product' ) ) ) {
wp_enqueue_media();
wp_enqueue_script( 'ajax-chosen' );
wp_enqueue_script( 'chosen' );
wp_enqueue_script( 'plupload-all' );
wp_enqueue_script( 'wc-admin-product-meta-boxes', WC()->plugin_url() . '/assets/js/admin/meta-boxes-product' . $suffix . '.js', array( 'wc-admin-meta-boxes' ), WC_VERSION );
wp_enqueue_script( 'wc-admin-variation-meta-boxes', WC()->plugin_url() . '/assets/js/admin/meta-boxes-product-variation' . $suffix . '.js', array( 'wc-admin-meta-boxes' ), WC_VERSION );
$params = array(
'post_id' => isset( $post->ID ) ? $post->ID : '',
'plugin_url' => WC()->plugin_url(),
'ajax_url' => admin_url('admin-ajax.php'),
'woocommerce_placeholder_img_src' => wc_placeholder_img_src(),
'add_variation_nonce' => wp_create_nonce("add-variation"),
'link_variation_nonce' => wp_create_nonce("link-variations"),
'delete_variation_nonce' => wp_create_nonce("delete-variation"),
'delete_variations_nonce' => wp_create_nonce("delete-variations"),
'i18n_link_all_variations' => esc_js( __( 'Are you sure you want to link all variations? This will create a new variation for each and every possible combination of variation attributes (max 50 per run).', 'woocommerce' ) ),
'i18n_enter_a_value' => esc_js( __( 'Enter a value', 'woocommerce' ) ),
'i18n_enter_a_value_fixed_or_percent' => esc_js( __( 'Enter a value (fixed or %)', 'woocommerce' ) ),
'i18n_delete_all_variations' => esc_js( __( 'Are you sure you want to delete all variations? This cannot be undone.', 'woocommerce' ) ),
'i18n_last_warning' => esc_js( __( 'Last warning, are you sure?', 'woocommerce' ) ),
'i18n_choose_image' => esc_js( __( 'Choose an image', 'woocommerce' ) ),
'i18n_set_image' => esc_js( __( 'Set variation image', 'woocommerce' ) ),
'i18n_variation_added' => esc_js( __( "variation added", 'woocommerce' ) ),
'i18n_variations_added' => esc_js( __( "variations added", 'woocommerce' ) ),
'i18n_no_variations_added' => esc_js( __( "No variations added", 'woocommerce' ) ),
'i18n_remove_variation' => esc_js( __( 'Are you sure you want to remove this variation?', 'woocommerce' ) )
);
wp_localize_script( 'wc-admin-variation-meta-boxes', 'woocommerce_admin_meta_boxes_variations', $params );
}
if ( in_array( str_replace( 'edit-', '', $screen->id ), wc_get_order_types( 'order-meta-boxes' ) ) ) {
wp_enqueue_script( 'wc-admin-order-meta-boxes', WC()->plugin_url() . '/assets/js/admin/meta-boxes-order' . $suffix . '.js', array( 'wc-admin-meta-boxes' ), WC_VERSION );
wp_enqueue_script( 'wc-admin-order-meta-boxes-modal', WC()->plugin_url() . '/assets/js/admin/order-backbone-modal' . $suffix . '.js', array( 'underscore', 'backbone', 'wc-admin-order-meta-boxes' ), WC_VERSION );
}
if ( in_array( $screen->id, array( 'shop_coupon', 'edit-shop_coupon' ) ) ) {
wp_enqueue_script( 'wc-admin-coupon-meta-boxes', WC()->plugin_url() . '/assets/js/admin/meta-boxes-coupon' . $suffix . '.js', array( 'wc-admin-meta-boxes' ), WC_VERSION );
}
if ( in_array( str_replace( 'edit-', '', $screen->id ), array_merge( array( 'shop_coupon', 'product' ), wc_get_order_types( 'order-meta-boxes' ) ) ) ) {
$params = array(
'remove_item_notice' => __( 'Are you sure you want to remove the selected items? If you have previously reduced this item\'s stock, or this order was submitted by a customer, you will need to manually restore the item\'s stock.', 'woocommerce' ),
'i18n_select_items' => __( 'Please select some items.', 'woocommerce' ),
'i18n_do_refund' => __( 'Are you sure you wish to process this refund? This action cannot be undone.', 'woocommerce' ),
'i18n_delete_refund' => __( 'Are you sure you wish to delete this refund? This action cannot be undone.', 'woocommerce' ),
'i18n_delete_tax' => __( 'Are you sure you wish to delete this tax column? This action cannot be undone.', 'woocommerce' ),
'remove_item_meta' => __( 'Remove this item meta?', 'woocommerce' ),
'remove_attribute' => __( 'Remove this attribute?', 'woocommerce' ),
'name_label' => __( 'Name', 'woocommerce' ),
@ -182,39 +213,10 @@ class WC_Admin_Assets {
'default_attribute_variation' => apply_filters( 'default_attribute_variation', false ),
'i18n_download_permission_fail' => __( 'Could not grant access - the user may already have permission for this file or billing email is not set. Ensure the billing email is set, and the order has been saved.', 'woocommerce' ),
'i18n_permission_revoke' => __( 'Are you sure you want to revoke access to this download?', 'woocommerce' ),
'i18n_tax_rate_already_exists' => __( 'You cannot add the same tax rate twice!', 'woocommerce' ),
);
wp_localize_script( 'woocommerce_admin_meta_boxes', 'woocommerce_admin_meta_boxes', $params );
}
// Product specific
if ( in_array( $screen->id, array( 'product', 'edit-product' ) ) ) {
wp_enqueue_script( 'woocommerce_admin_meta_boxes_variations' );
$params = array(
'post_id' => isset( $post->ID ) ? $post->ID : '',
'plugin_url' => WC()->plugin_url(),
'ajax_url' => admin_url('admin-ajax.php'),
'woocommerce_placeholder_img_src' => wc_placeholder_img_src(),
'add_variation_nonce' => wp_create_nonce("add-variation"),
'link_variation_nonce' => wp_create_nonce("link-variations"),
'delete_variation_nonce' => wp_create_nonce("delete-variation"),
'delete_variations_nonce' => wp_create_nonce("delete-variations"),
'i18n_link_all_variations' => esc_js( __( 'Are you sure you want to link all variations? This will create a new variation for each and every possible combination of variation attributes (max 50 per run).', 'woocommerce' ) ),
'i18n_enter_a_value' => esc_js( __( 'Enter a value', 'woocommerce' ) ),
'i18n_enter_a_value_fixed_or_percent' => esc_js( __( 'Enter a value (fixed or %)', 'woocommerce' ) ),
'i18n_delete_all_variations' => esc_js( __( 'Are you sure you want to delete all variations? This cannot be undone.', 'woocommerce' ) ),
'i18n_last_warning' => esc_js( __( 'Last warning, are you sure?', 'woocommerce' ) ),
'i18n_choose_image' => esc_js( __( 'Choose an image', 'woocommerce' ) ),
'i18n_set_image' => esc_js( __( 'Set variation image', 'woocommerce' ) ),
'i18n_variation_added' => esc_js( __( "variation added", 'woocommerce' ) ),
'i18n_variations_added' => esc_js( __( "variations added", 'woocommerce' ) ),
'i18n_no_variations_added' => esc_js( __( "No variations added", 'woocommerce' ) ),
'i18n_remove_variation' => esc_js( __( 'Are you sure you want to remove this variation?', 'woocommerce' ) )
);
wp_localize_script( 'woocommerce_admin_meta_boxes_variations', 'woocommerce_admin_meta_boxes_variations', $params );
wp_localize_script( 'wc-admin-meta-boxes', 'woocommerce_admin_meta_boxes', $params );
}
// Term ordering - only when sorting by term_order

View File

@ -52,7 +52,7 @@ class WC_Admin_Dashboard {
$query = array();
$query['fields'] = "SELECT SUM( postmeta.meta_value ) FROM {$wpdb->posts} as posts";
$query['join'] = "INNER JOIN {$wpdb->postmeta} AS postmeta ON posts.ID = postmeta.post_id ";
$query['where'] = "WHERE posts.post_type = 'shop_order' ";
$query['where'] = "WHERE posts.post_type IN ( '" . implode( "','", wc_get_order_types( 'reports' ) ) . "' ) ";
$query['where'] .= "AND posts.post_status IN ( 'wc-" . implode( "','wc-", apply_filters( 'woocommerce_reports_order_statuses', array( 'completed', 'processing', 'on-hold' ) ) ) . "' ) ";
$query['where'] .= "AND postmeta.meta_key = '_order_total' ";
$query['where'] .= "AND posts.post_date >= '" . date( 'Y-m-01', current_time( 'timestamp' ) ) . "' ";
@ -67,7 +67,7 @@ class WC_Admin_Dashboard {
$query['join'] = "INNER JOIN {$wpdb->prefix}woocommerce_order_items AS order_items ON posts.ID = order_id ";
$query['join'] .= "INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS order_item_meta ON order_items.order_item_id = order_item_meta.order_item_id ";
$query['join'] .= "INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS order_item_meta_2 ON order_items.order_item_id = order_item_meta_2.order_item_id ";
$query['where'] = "WHERE posts.post_type = 'shop_order' ";
$query['where'] = "WHERE posts.post_type IN ( '" . implode( "','", wc_get_order_types( 'order-count' ) ) . "' ) ";
$query['where'] .= "AND posts.post_status IN ( 'wc-" . implode( "','wc-", apply_filters( 'woocommerce_reports_order_statuses', array( 'completed', 'processing', 'on-hold' ) ) ) . "' ) ";
$query['where'] .= "AND order_item_meta.meta_key = '_qty' ";
$query['where'] .= "AND order_item_meta_2.meta_key = '_product_id' ";
@ -80,9 +80,14 @@ class WC_Admin_Dashboard {
$top_seller = $wpdb->get_row( implode( ' ', apply_filters( 'woocommerce_dashboard_status_widget_top_seller_query', $query ) ) );
// Counts
$counts = (array) wp_count_posts( 'shop_order' );
$on_hold_count = $counts['wc-on-hold'];
$processing_count = $counts['wc-processing'];
$on_hold_count = 0;
$processing_count = 0;
foreach ( wc_get_order_types( 'order-count' ) as $type ) {
$counts = (array) wp_count_posts( $type );
$on_hold_count += isset( $counts['wc-on-hold'] ) ? $counts['wc-on-hold'] : 0;
$processing_count += isset( $counts['wc-processing'] ) ? $counts['wc-processing'] : 0;
}
// Get products using a query - this is too advanced for get_posts :(
$stock = absint( max( get_option( 'woocommerce_notify_low_stock_amount' ), 1 ) );

View File

@ -40,7 +40,6 @@ class WC_Admin_Meta_Boxes {
* Save actions - sends out other emails. Last to show latest data.
*/
add_action( 'woocommerce_process_shop_order_meta', 'WC_Meta_Box_Order_Items::save', 10, 2 );
add_action( 'woocommerce_process_shop_order_meta', 'WC_Meta_Box_Order_Totals::save', 20, 2 );
add_action( 'woocommerce_process_shop_order_meta', 'WC_Meta_Box_Order_Downloads::save', 30, 2 );
add_action( 'woocommerce_process_shop_order_meta', 'WC_Meta_Box_Order_Data::save', 40, 2 );
add_action( 'woocommerce_process_shop_order_meta', 'WC_Meta_Box_Order_Actions::save', 50, 2 );
@ -104,12 +103,13 @@ class WC_Admin_Meta_Boxes {
add_meta_box( 'woocommerce-product-images', __( 'Product Gallery', 'woocommerce' ), 'WC_Meta_Box_Product_Images::output', 'product', 'side' );
// Orders
add_meta_box( 'woocommerce-order-data', __( 'Order Data', 'woocommerce' ), 'WC_Meta_Box_Order_Data::output', 'shop_order', 'normal', 'high' );
add_meta_box( 'woocommerce-order-items', __( 'Order Items', 'woocommerce' ), 'WC_Meta_Box_Order_Items::output', 'shop_order', 'normal', 'high' );
add_meta_box( 'woocommerce-order-totals', __( 'Order Totals', 'woocommerce' ), 'WC_Meta_Box_Order_Totals::output', 'shop_order', 'side', 'default' );
add_meta_box( 'woocommerce-order-notes', __( 'Order Notes', 'woocommerce' ), 'WC_Meta_Box_Order_Notes::output', 'shop_order', 'side', 'default' );
add_meta_box( 'woocommerce-order-downloads', __( 'Downloadable Product Permissions', 'woocommerce' ) . ' <span class="tips" data-tip="' . __( 'Note: Permissions for order items will automatically be granted when the order status changes to processing/completed.', 'woocommerce' ) . '">[?]</span>', 'WC_Meta_Box_Order_Downloads::output', 'shop_order', 'normal', 'default' );
add_meta_box( 'woocommerce-order-actions', __( 'Order Actions', 'woocommerce' ), 'WC_Meta_Box_Order_Actions::output', 'shop_order', 'side', 'high' );
foreach ( wc_get_order_types( 'order-meta-boxes' ) as $type ) {
add_meta_box( 'woocommerce-order-data', __( 'Order Data', 'woocommerce' ), 'WC_Meta_Box_Order_Data::output', $type, 'normal', 'high' );
add_meta_box( 'woocommerce-order-items', __( 'Order Items', 'woocommerce' ), 'WC_Meta_Box_Order_Items::output', $type, 'normal', 'high' );
add_meta_box( 'woocommerce-order-notes', __( 'Order Notes', 'woocommerce' ), 'WC_Meta_Box_Order_Notes::output', $type, 'side', 'default' );
add_meta_box( 'woocommerce-order-downloads', __( 'Downloadable Product Permissions', 'woocommerce' ) . ' <span class="tips" data-tip="' . __( 'Note: Permissions for order items will automatically be granted when the order status changes to processing/completed.', 'woocommerce' ) . '">[?]</span>', 'WC_Meta_Box_Order_Downloads::output', $type, 'normal', 'default' );
add_meta_box( 'woocommerce-order-actions', __( 'Order Actions', 'woocommerce' ), 'WC_Meta_Box_Order_Actions::output', $type, 'side', 'high' );
}
// Coupons
add_meta_box( 'woocommerce-coupon-data', __( 'Coupon Data', 'woocommerce' ), 'WC_Meta_Box_Coupon_Data::output', 'shop_coupon', 'normal', 'high' );
@ -134,10 +134,13 @@ class WC_Admin_Meta_Boxes {
remove_meta_box( 'woothemes-settings', 'shop_coupon' , 'normal' );
remove_meta_box( 'commentstatusdiv', 'shop_coupon' , 'normal' );
remove_meta_box( 'slugdiv', 'shop_coupon' , 'normal' );
remove_meta_box( 'commentsdiv', 'shop_order' , 'normal' );
remove_meta_box( 'woothemes-settings', 'shop_order' , 'normal' );
remove_meta_box( 'commentstatusdiv', 'shop_order' , 'normal' );
remove_meta_box( 'slugdiv', 'shop_order' , 'normal' );
foreach ( wc_get_order_types( 'order-meta-boxes' ) as $type ) {
remove_meta_box( 'commentsdiv', $type, 'normal' );
remove_meta_box( 'woothemes-settings', $type, 'normal' );
remove_meta_box( 'commentstatusdiv', $type, 'normal' );
remove_meta_box( 'slugdiv', $type, 'normal' );
}
}
/**
@ -187,12 +190,12 @@ class WC_Admin_Meta_Boxes {
}
// Check the post type
if ( ! in_array( $post->post_type, array( 'product', 'shop_order', 'shop_coupon' ) ) ) {
return;
}
if ( in_array( $post->post_type, wc_get_order_types( 'order-meta-boxes' ) ) ) {
do_action( 'woocommerce_process_shop_order_meta', $post_id, $post );
} elseif ( in_array( $post->post_type, array( 'product', 'shop_coupon' ) ) ) {
do_action( 'woocommerce_process_' . $post->post_type . '_meta', $post_id, $post );
}
}
}

View File

@ -1524,6 +1524,7 @@ class WC_Admin_Post_Types {
}
} elseif ( 'shop_order' === $typenow ) {
// Filter the orders by the posted customer.
if ( isset( $_GET['_customer_user'] ) && $_GET['_customer_user'] > 0 ) {
$vars['meta_key'] = '_customer_user';
@ -1733,6 +1734,13 @@ class WC_Admin_Post_Types {
case 'product_variation' :
wc_delete_product_transients( wp_get_post_parent_id( $id ) );
break;
case 'shop_order' :
$refunds = $wpdb->get_results( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type = 'shop_order_refund' AND post_parent = %d", $id ) );
foreach ( $refunds as $refund ) {
wp_delete_post( $refund->ID, true );
}
break;
}
}
}
@ -1745,6 +1753,8 @@ class WC_Admin_Post_Types {
* @return void
*/
public function trash_post( $id ) {
global $wpdb;
if ( $id > 0 ) {
$post_type = get_post_type( $id );
@ -1759,6 +1769,12 @@ class WC_Admin_Post_Types {
update_user_meta( $user_id, '_money_spent', '' );
}
$refunds = $wpdb->get_results( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type = 'shop_order_refund' AND post_parent = %d", $id ) );
foreach ( $refunds as $refund ) {
$wpdb->update( $wpdb->posts, array( 'post_status' => 'trash' ), array( 'ID' => $refund->ID ) );
}
delete_transient( 'woocommerce_processing_order_count' );
}
@ -1773,6 +1789,8 @@ class WC_Admin_Post_Types {
* @return void
*/
public function untrash_post( $id ) {
global $wpdb;
if ( $id > 0 ) {
$post_type = get_post_type( $id );
@ -1787,6 +1805,12 @@ class WC_Admin_Post_Types {
update_user_meta( $user_id, '_money_spent', '' );
}
$refunds = $wpdb->get_results( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_type = 'shop_order_refund' AND post_parent = %d", $id ) );
foreach ( $refunds as $refund ) {
$wpdb->update( $wpdb->posts, array( 'post_status' => 'wc-completed' ), array( 'ID' => $refund->ID ) );
}
delete_transient( 'woocommerce_processing_order_count' );
}

View File

@ -20,8 +20,9 @@ class WC_Meta_Box_Order_Actions {
public static function output( $post ) {
global $theorder;
if ( ! is_object( $theorder ) )
if ( ! is_object( $theorder ) ) {
$theorder = get_order( $post->ID );
}
$order = $theorder;
?>
@ -32,10 +33,13 @@ class WC_Meta_Box_Order_Actions {
<li class="wide" id="actions">
<select name="wc_order_action">
<option value=""><?php _e( 'Actions', 'woocommerce' ); ?></option>
<option value="refund_order"><?php _e( 'Refund this order', 'woocommerce' ); ?></option>
<option value="refund_order"><?php _e( 'Cancel this order', 'woocommerce' ); ?></option>
<optgroup label="<?php _e( 'Resend order emails', 'woocommerce' ); ?>">
<?php
$mailer = WC()->mailer();
$available_emails = apply_filters( 'woocommerce_resend_order_emails_available', array( 'new_order', 'customer_processing_order', 'customer_completed_order', 'customer_invoice' ) );
$mails = $mailer->get_emails();
@ -48,7 +52,9 @@ class WC_Meta_Box_Order_Actions {
}
?>
</optgroup>
<option value="regenerate_download_permissions"><?php _e( 'Generate Download Permissions', 'woocommerce' ); ?></option>
<option value="regenerate_download_permissions"><?php _e( 'Generate download permissions', 'woocommerce' ); ?></option>
<?php foreach( apply_filters( 'woocommerce_order_actions', array() ) as $action => $title ) { ?>
<option value="<?php echo $action; ?>"><?php echo $title; ?></option>
<?php } ?>
@ -60,10 +66,11 @@ class WC_Meta_Box_Order_Actions {
<li class="wide">
<div id="delete-action"><?php
if ( current_user_can( "delete_post", $post->ID ) ) {
if ( ! EMPTY_TRASH_DAYS )
if ( ! EMPTY_TRASH_DAYS ) {
$delete_text = __( 'Delete Permanently', 'woocommerce' );
else
} else {
$delete_text = __( 'Move to Trash', 'woocommerce' );
}
?><a class="submitdelete deletion" href="<?php echo esc_url( get_delete_post_link( $post->ID ) ); ?>"><?php echo $delete_text; ?></a><?php
}
?></div>
@ -119,6 +126,11 @@ class WC_Meta_Box_Order_Actions {
delete_post_meta( $post_id, '_download_permissions_granted' );
wc_downloadable_product_permissions( $post_id );
} elseif ( $action = 'create_credit_note' ) {
wp_redirect( admin_url( 'post-new.php?post_type=wc_credit_note&order_id=' . $post_id ) );
exit;
} else {
do_action( 'woocommerce_order_action_' . sanitize_title( $action ), $order );

View File

@ -162,7 +162,7 @@ class WC_Meta_Box_Order_Data {
if ( $payment_method ) {
printf( __( 'Payment via %s', 'woocommerce' ), ( isset( $payment_gateways[ $payment_method ] ) ? esc_html( $payment_gateways[ $payment_method ]->get_title() ) : esc_html( $payment_method ) ) );
if ( $transaction_id = get_post_meta( $order->id, '_transaction_id', true ) ) {
if ( $transaction_id = $order->get_transaction_id() ) {
if ( isset( $payment_gateways[ $payment_method ] ) && ( $url = $payment_gateways[ $payment_method ]->get_transaction_url( $transaction_id ) ) ) {
echo ' (<a href="' . esc_url( $url ) . '" target="_blank">' . esc_html( $transaction_id ) . '</a>)';
} else {

View File

@ -20,163 +20,20 @@ class WC_Meta_Box_Order_Items {
public static function output( $post ) {
global $thepostid, $theorder;
if ( ! is_object( $theorder ) )
if ( ! is_object( $theorder ) ) {
$theorder = get_order( $thepostid );
}
$order = $theorder;
?>
<div class="woocommerce_order_items_wrapper">
<table cellpadding="0" cellspacing="0" class="woocommerce_order_items">
<thead>
<tr>
<th><input type="checkbox" class="check-column" /></th>
<th class="item" colspan="2"><?php _e( 'Item', 'woocommerce' ); ?></th>
$data = get_post_meta( $post->ID );
<?php do_action( 'woocommerce_admin_order_item_headers' ); ?>
<?php if ( get_option( 'woocommerce_calc_taxes' ) == 'yes' ) : ?>
<th class="tax_class"><?php _e( 'Tax&nbsp;Class', 'woocommerce' ); ?></th>
<?php endif; ?>
<th class="quantity"><?php _e( 'Qty', 'woocommerce' ); ?></th>
<th class="line_cost"><?php _e( 'Total', 'woocommerce' ); ?></th>
<?php if ( get_option( 'woocommerce_calc_taxes' ) == 'yes' ) : ?>
<th class="line_tax"><?php _e( 'Tax', 'woocommerce' ); ?></th>
<?php endif; ?>
<th width="1%">&nbsp;</th>
</tr>
</thead>
<tbody id="order_items_list">
<?php
// List order items
$order_items = $order->get_items( apply_filters( 'woocommerce_admin_order_item_types', array( 'line_item', 'fee' ) ) );
foreach ( $order_items as $item_id => $item ) {
switch ( $item['type'] ) {
case 'line_item' :
$_product = $order->get_product_from_item( $item );
$item_meta = $order->get_item_meta( $item_id );
include( 'views/html-order-item.php' );
break;
case 'fee' :
include( 'views/html-order-fee.php' );
break;
}
do_action( 'woocommerce_order_item_' . $item['type'] . '_html', $item_id, $item );
}
?>
</tbody>
</table>
</div>
<p class="bulk_actions">
<select>
<option value=""><?php _e( 'Actions', 'woocommerce' ); ?></option>
<optgroup label="<?php _e( 'Edit', 'woocommerce' ); ?>">
<option value="delete"><?php _e( 'Delete Lines', 'woocommerce' ); ?></option>
</optgroup>
<optgroup label="<?php _e( 'Stock Actions', 'woocommerce' ); ?>">
<option value="reduce_stock"><?php _e( 'Reduce Line Stock', 'woocommerce' ); ?></option>
<option value="increase_stock"><?php _e( 'Increase Line Stock', 'woocommerce' ); ?></option>
</optgroup>
</select>
<button type="button" class="button do_bulk_action wc-reload" title="<?php _e( 'Apply', 'woocommerce' ); ?>"><span><?php _e( 'Apply', 'woocommerce' ); ?></span></button>
</p>
<p class="add_items">
<select id="add_item_id" class="ajax_chosen_select_products_and_variations" multiple="multiple" data-placeholder="<?php _e( 'Search for a product&hellip;', 'woocommerce' ); ?>" style="width: 400px"></select>
<button type="button" class="button add_order_item"><?php _e( 'Add item(s)', 'woocommerce' ); ?></button>
<button type="button" class="button add_order_fee"><?php _e( 'Add fee', 'woocommerce' ); ?></button>
</p>
<div class="clear"></div>
<?php
include( 'views/html-order-items.php' );
}
/**
* Save meta box data
*/
public static function save( $post_id, $post ) {
global $wpdb;
// Order items + fees
$subtotal = 0;
$total = 0;
if ( isset( $_POST['order_item_id'] ) ) {
$get_values = array( 'order_item_id', 'order_item_name', 'order_item_qty', 'line_subtotal', 'line_subtotal_tax', 'line_total', 'line_tax', 'order_item_tax_class' );
foreach( $get_values as $value )
$$value = isset( $_POST[ $value ] ) ? $_POST[ $value ] : array();
foreach ( $order_item_id as $item_id ) {
$item_id = absint( $item_id );
if ( isset( $order_item_name[ $item_id ] ) )
$wpdb->update(
$wpdb->prefix . "woocommerce_order_items",
array( 'order_item_name' => wc_clean( $order_item_name[ $item_id ] ) ),
array( 'order_item_id' => $item_id ),
array( '%s' ),
array( '%d' )
);
if ( isset( $order_item_qty[ $item_id ] ) )
wc_update_order_item_meta( $item_id, '_qty', wc_stock_amount( $order_item_qty[ $item_id ] ) );
if ( isset( $order_item_tax_class[ $item_id ] ) )
wc_update_order_item_meta( $item_id, '_tax_class', wc_clean( $order_item_tax_class[ $item_id ] ) );
// Get values. Subtotals might not exist, in which case copy value from total field
$line_total[ $item_id ] = isset( $line_total[ $item_id ] ) ? $line_total[ $item_id ] : 0;
$line_tax[ $item_id ] = isset( $line_tax[ $item_id ] ) ? $line_tax[ $item_id ] : 0;
$line_subtotal[ $item_id ] = isset( $line_subtotal[ $item_id ] ) ? $line_subtotal[ $item_id ] : $line_total[ $item_id ];
$line_subtotal_tax[ $item_id ] = isset( $line_subtotal_tax[ $item_id ] ) ? $line_subtotal_tax[ $item_id ] : $line_tax[ $item_id ];
// Update values
wc_update_order_item_meta( $item_id, '_line_subtotal', wc_format_decimal( $line_subtotal[ $item_id ] ) );
wc_update_order_item_meta( $item_id, '_line_subtotal_tax', wc_format_decimal( $line_subtotal_tax[ $item_id ] ) );
wc_update_order_item_meta( $item_id, '_line_total', wc_format_decimal( $line_total[ $item_id ] ) );
wc_update_order_item_meta( $item_id, '_line_tax', wc_format_decimal( $line_tax[ $item_id ] ) );
// Total up
$subtotal += wc_format_decimal( $line_subtotal[ $item_id ] );
$total += wc_format_decimal( $line_total[ $item_id ] );
// Clear meta cache
wp_cache_delete( $item_id, 'order_item_meta' );
}
}
// Save meta
$meta_keys = isset( $_POST['meta_key'] ) ? $_POST['meta_key'] : array();
$meta_values = isset( $_POST['meta_value'] ) ? $_POST['meta_value'] : array();
foreach ( $meta_keys as $id => $meta_key ) {
$meta_value = ( empty( $meta_values[ $id ] ) && ! is_numeric( $meta_values[ $id ] ) ) ? '' : $meta_values[ $id ];
$wpdb->update(
$wpdb->prefix . "woocommerce_order_itemmeta",
array(
'meta_key' => wp_unslash($meta_key),
'meta_value' => wp_unslash($meta_value)
),
array( 'meta_id' => $id ),
array( '%s', '%s' ),
array( '%d' )
);
}
// Update cart discount from item totals
update_post_meta( $post_id, '_cart_discount', $subtotal - $total );
wc_save_order_items( $post_id, $_POST );
}
}

View File

@ -1,345 +0,0 @@
<?php
/**
* Order Totals
*
* Functions for displaying the order totals meta box.
*
* @author WooThemes
* @category Admin
* @package WooCommerce/Admin/Meta Boxes
* @version 2.1.0
*/
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
class WC_Meta_Box_Order_Totals {
/**
* Output the metabox
*/
public static function output() {
global $theorder, $wpdb, $post;
if ( ! is_object( $theorder ) )
$theorder = get_order( $post->ID );
$order = $theorder;
$data = get_post_meta( $post->ID );
?>
<div class="totals_group">
<h4><span class="tax_total_display inline_total"></span><?php _e( 'Shipping', 'woocommerce' ); ?></h4>
<div id="shipping_rows" class="total_rows">
<?php
if ( WC()->shipping() )
$shipping_methods = WC()->shipping->load_shipping_methods();
foreach ( $order->get_shipping_methods() as $item_id => $item ) {
$chosen_method = $item['method_id'];
$shipping_title = $item['name'];
$shipping_cost = $item['cost'];
include( 'views/html-order-shipping.php' );
}
// Pre 2.1
if ( isset( $data['_shipping_method'] ) ) {
$item_id = '';
$chosen_method = ! empty( $data['_shipping_method'][0] ) ? $data['_shipping_method'][0] : '';
$shipping_title = ! empty( $data['_shipping_method_title'][0] ) ? $data['_shipping_method_title'][0] : '';
$shipping_cost = ! empty( $data['_order_shipping'][0] ) ? $data['_order_shipping'][0] : '';
include( 'views/html-order-shipping.php' );
}
?>
</div>
<h4><a href="#" class="add_total_row" data-row="<?php
$item_id = '';
$chosen_method = '';
$shipping_cost = '';
$shipping_title = __( 'Shipping', 'woocommerce' );
ob_start();
include( 'views/html-order-shipping.php' );
echo esc_attr( ob_get_clean() );
?>"><?php _e( '+ Add shipping cost', 'woocommerce' ); ?> <span class="tips" data-tip="<?php _e( 'These are the shipping and handling costs for the order.', 'woocommerce' ); ?>">[?]</span></a></a></h4>
<div class="clear"></div>
<?php do_action( 'woocommerce_admin_order_totals_after_shipping', $post->ID ) ?>
</div>
<?php if ( get_option( 'woocommerce_calc_taxes' ) == 'yes' ) : ?>
<div class="totals_group tax_rows_group">
<h4><span class="tax_total_display inline_total"></span><?php _e( 'Taxes', 'woocommerce' ); ?></h4>
<div id="tax_rows" class="total_rows">
<?php
global $wpdb;
$rates = $wpdb->get_results( "SELECT tax_rate_id, tax_rate_country, tax_rate_state, tax_rate_name, tax_rate_priority FROM {$wpdb->prefix}woocommerce_tax_rates ORDER BY tax_rate_name" );
$tax_codes = array();
foreach( $rates as $rate ) {
$code = array();
$code[] = $rate->tax_rate_country;
$code[] = $rate->tax_rate_state;
$code[] = $rate->tax_rate_name ? sanitize_title( $rate->tax_rate_name ) : 'TAX';
$code[] = absint( $rate->tax_rate_priority );
$tax_codes[ $rate->tax_rate_id ] = strtoupper( implode( '-', array_filter( $code ) ) );
}
foreach ( $order->get_taxes() as $item_id => $item ) {
include( 'views/html-order-tax.php' );
}
?>
</div>
<h4><a href="#" class="add_total_row" data-row="<?php
$item_id = '';
$item = '';
ob_start();
include( 'views/html-order-tax.php' );
echo esc_attr( ob_get_clean() );
?>"><?php _e( '+ Add tax row', 'woocommerce' ); ?> <span class="tips" data-tip="<?php _e( 'These rows contain taxes for this order. This allows you to display multiple or compound taxes rather than a single total.', 'woocommerce' ); ?>">[?]</span></a></a></h4>
<div class="clear"></div>
</div>
<?php endif; ?>
<div class="totals_group">
<h4><label for="_order_discount"><?php _e( 'Order Discount', 'woocommerce' ); ?> <span class="tips" data-tip="<?php _e( 'This is the total discount applied after tax.', 'woocommerce' ); ?>">[?]</span></label></h4>
<input type="text" class="wc_input_price" id="_order_discount" name="_order_discount" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php
if ( isset( $data['_order_discount'][0] ) )
echo esc_attr( wc_format_localized_price( $data['_order_discount'][0] ) );
?>" />
</div>
<div class="totals_group">
<h4><label for="_order_total"><?php _e( 'Order Total', 'woocommerce' ); ?></label></h4>
<input type="text" class="wc_input_price" id="_order_total" name="_order_total" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php
if ( isset( $data['_order_total'][0] ) )
echo esc_attr( wc_format_localized_price( $data['_order_total'][0] ) );
?>" />
</div>
<?php
$coupons = $order->get_items( array( 'coupon' ) );
if ( $coupons ) {
?>
<div class="totals_group">
<ul class="wc_coupon_list"><?php
foreach ( $coupons as $item_id => $item ) {
$post_id = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_title = %s AND post_type = 'shop_coupon' AND post_status = 'publish' LIMIT 1;", $item['name'] ) );
$link = $post_id ? add_query_arg( array( 'post' => $post_id, 'action' => 'edit' ), admin_url( 'post.php' ) ) : add_query_arg( array( 's' => $item['name'], 'post_status' => 'all', 'post_type' => 'shop_coupon' ), admin_url( 'edit.php' ) );
echo '<li class="tips code" data-tip="' . esc_attr( wc_price( $item['discount_amount'] ) ) . '"><a href="' . esc_url( $link ) . '"><span>' . esc_html( $item['name'] ). '</span></a></li>';
}
?></ul>
</div>
<?php
}
?>
<p class="buttons">
<?php if ( get_option( 'woocommerce_calc_taxes' ) == 'yes' ) : ?>
<button type="button" class="button calc_line_taxes"><?php _e( 'Calculate Tax', 'woocommerce' ); ?></button>
<?php endif; ?>
<button type="button" class="button calc_totals button-primary"><?php _e( 'Calculate Total', 'woocommerce' ); ?></button>
</p>
<?php
}
/**
* Save meta box data
*/
public static function save( $post_id, $post ) {
global $wpdb;
// Save tax rows
$total_tax = 0;
$total_shipping_tax = 0;
if ( isset( $_POST['order_taxes_id'] ) ) {
$get_values = array( 'order_taxes_id', 'order_taxes_rate_id', 'order_taxes_amount', 'order_taxes_shipping_amount' );
foreach( $get_values as $value )
$$value = isset( $_POST[ $value ] ) ? $_POST[ $value ] : array();
foreach( $order_taxes_id as $item_id => $value ) {
if ( $item_id == 'new' ) {
foreach ( $value as $new_key => $new_value ) {
$rate_id = absint( $order_taxes_rate_id[ $item_id ][ $new_key ] );
if ( $rate_id ) {
$rate = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %s", $rate_id ) );
$label = $rate->tax_rate_name ? $rate->tax_rate_name : WC()->countries->tax_or_vat();
$compound = $rate->tax_rate_compound ? 1 : 0;
$code = array();
$code[] = $rate->tax_rate_country;
$code[] = $rate->tax_rate_state;
$code[] = $rate->tax_rate_name ? $rate->tax_rate_name : 'TAX';
$code[] = absint( $rate->tax_rate_priority );
$code = strtoupper( implode( '-', array_filter( $code ) ) );
} else {
$code = '';
$label = WC()->countries->tax_or_vat();
}
// Add line item
$new_id = wc_add_order_item( $post_id, array(
'order_item_name' => wc_clean( $code ),
'order_item_type' => 'tax'
) );
// Add line item meta
if ( $new_id ) {
wc_update_order_item_meta( $new_id, 'rate_id', $rate_id );
wc_update_order_item_meta( $new_id, 'label', $label );
wc_update_order_item_meta( $new_id, 'compound', $compound );
if ( isset( $order_taxes_amount[ $item_id ][ $new_key ] ) ) {
wc_update_order_item_meta( $new_id, 'tax_amount', wc_format_decimal( $order_taxes_amount[ $item_id ][ $new_key ] ) );
$total_tax += wc_format_decimal( $order_taxes_amount[ $item_id ][ $new_key ] );
}
if ( isset( $order_taxes_shipping_amount[ $item_id ][ $new_key ] ) ) {
wc_update_order_item_meta( $new_id, 'shipping_tax_amount', wc_format_decimal( $order_taxes_shipping_amount[ $item_id ][ $new_key ] ) );
$total_shipping_tax += wc_format_decimal( $order_taxes_shipping_amount[ $item_id ][ $new_key ] );
}
}
}
} else {
$item_id = absint( $item_id );
$rate_id = absint( $order_taxes_rate_id[ $item_id ] );
if ( $rate_id ) {
$rate = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %s", $rate_id ) );
$label = $rate->tax_rate_name ? $rate->tax_rate_name : WC()->countries->tax_or_vat();
$compound = $rate->tax_rate_compound ? 1 : 0;
$code = array();
$code[] = $rate->tax_rate_country;
$code[] = $rate->tax_rate_state;
$code[] = $rate->tax_rate_name ? $rate->tax_rate_name : 'TAX';
$code[] = absint( $rate->tax_rate_priority );
$code = strtoupper( implode( '-', array_filter( $code ) ) );
} else {
$code = '';
$label = WC()->countries->tax_or_vat();
}
$wpdb->update(
$wpdb->prefix . "woocommerce_order_items",
array( 'order_item_name' => wc_clean( $code ) ),
array( 'order_item_id' => $item_id ),
array( '%s' ),
array( '%d' )
);
wc_update_order_item_meta( $item_id, 'rate_id', $rate_id );
wc_update_order_item_meta( $item_id, 'label', $label );
wc_update_order_item_meta( $item_id, 'compound', $compound );
if ( isset( $order_taxes_amount[ $item_id ] ) ) {
wc_update_order_item_meta( $item_id, 'tax_amount', wc_format_decimal( $order_taxes_amount[ $item_id ] ) );
$total_tax += wc_format_decimal( $order_taxes_amount[ $item_id ] );
}
if ( isset( $order_taxes_shipping_amount[ $item_id ] ) ) {
wc_update_order_item_meta( $item_id, 'shipping_tax_amount', wc_format_decimal( $order_taxes_shipping_amount[ $item_id ] ) );
$total_shipping_tax += wc_format_decimal( $order_taxes_shipping_amount[ $item_id ] );
}
}
}
}
// Update totals
update_post_meta( $post_id, '_order_tax', wc_format_decimal( $total_tax ) );
update_post_meta( $post_id, '_order_shipping_tax', wc_format_decimal( $total_shipping_tax ) );
update_post_meta( $post_id, '_order_discount', wc_format_decimal( $_POST['_order_discount'] ) );
update_post_meta( $post_id, '_order_total', wc_format_decimal( $_POST['_order_total'] ) );
// Shipping Rows
$order_shipping = 0;
if ( isset( $_POST['shipping_method_id'] ) ) {
$get_values = array( 'shipping_method_id', 'shipping_method_title', 'shipping_method', 'shipping_cost' );
foreach( $get_values as $value )
$$value = isset( $_POST[ $value ] ) ? $_POST[ $value ] : array();
foreach( $shipping_method_id as $item_id => $value ) {
if ( $item_id == 'new' ) {
foreach ( $value as $new_key => $new_value ) {
$method_id = wc_clean( $shipping_method[ $item_id ][ $new_key ] );
$method_title = wc_clean( $shipping_method_title[ $item_id ][ $new_key ] );
$cost = wc_format_decimal( $shipping_cost[ $item_id ][ $new_key ] );
$new_id = wc_add_order_item( $post_id, array(
'order_item_name' => $method_title,
'order_item_type' => 'shipping'
) );
if ( $new_id ) {
wc_add_order_item_meta( $new_id, 'method_id', $method_id );
wc_add_order_item_meta( $new_id, 'cost', $cost );
}
$order_shipping += $cost;
}
} else {
$item_id = absint( $item_id );
$method_id = wc_clean( $shipping_method[ $item_id ] );
$method_title = wc_clean( $shipping_method_title[ $item_id ] );
$cost = wc_format_decimal( $shipping_cost[ $item_id ] );
$wpdb->update(
$wpdb->prefix . "woocommerce_order_items",
array( 'order_item_name' => $method_title ),
array( 'order_item_id' => $item_id ),
array( '%s' ),
array( '%d' )
);
wc_update_order_item_meta( $item_id, 'method_id', $method_id );
wc_update_order_item_meta( $item_id, 'cost', $cost );
$order_shipping += $cost;
}
}
}
// Delete rows
if ( isset( $_POST['delete_order_item_id'] ) ) {
$delete_ids = $_POST['delete_order_item_id'];
foreach ( $delete_ids as $id )
wc_delete_order_item( absint( $id ) );
}
delete_post_meta( $post_id, '_shipping_method' );
delete_post_meta( $post_id, '_shipping_method_title' );
update_post_meta( $post_id, '_order_shipping', $order_shipping );
add_post_meta( $post_id, '_order_currency', get_woocommerce_currency(), true );
}
}

View File

@ -6,79 +6,80 @@ if ( ! defined( 'ABSPATH' ) ) {
<tr class="fee <?php echo ( ! empty( $class ) ) ? $class : ''; ?>" data-order_item_id="<?php echo $item_id; ?>">
<td class="check-column"><input type="checkbox" /></td>
<td class="thumb"></td>
<td class="thumb"><div></div></td>
<td class="name">
<div class="view">
<?php echo ! empty( $item['name'] ) ? esc_html( $item['name'] ) : __( 'Fee', 'woocommerce' ); ?>
</div>
<div class="edit" style="display:none">
<div class="edit" style="display: none;">
<input type="text" placeholder="<?php _e( 'Fee Name', 'woocommerce' ); ?>" name="order_item_name[<?php echo absint( $item_id ); ?>]" value="<?php echo ( isset( $item['name'] ) ) ? esc_attr( $item['name'] ) : ''; ?>" />
<input type="hidden" class="order_item_id" name="order_item_id[]" value="<?php echo esc_attr( $item_id ); ?>" />
<input type="hidden" name="order_item_tax_class[<?php echo absint( $item_id ); ?>]" value="<?php echo isset( $item['tax_class'] ) ? esc_attr( $item['tax_class'] ) : ''; ?>" />
</div>
</td>
<?php if ( 'yes' == get_option( 'woocommerce_calc_taxes' ) ) :
$tax_classes = array_filter( array_map( 'trim', explode( "\n", get_option( 'woocommerce_tax_classes' ) ) ) );
$classes_options = array();
$classes_options[''] = __( 'Standard', 'woocommerce' );
$tax_class = isset( $item['tax_class'] ) ? sanitize_title( $item['tax_class'] ) : '';
<?php do_action( 'woocommerce_admin_order_item_values', null, $item, absint( $item_id ) ); ?>
if ( $tax_classes ) {
foreach ( $tax_classes as $class ) {
$classes_options[ sanitize_title( $class ) ] = $class;
}
}
?>
<td class="tax_class" width="1%">
<div class="view">
<?php
$item_value = isset( $classes_options[ $tax_class ] ) ? esc_attr( $classes_options[ $tax_class ] ) : '';
echo $item_value ? $item_value : __( 'Standard', 'woocommerce' );
?>
</div>
<div class="edit" style="display:none">
<select class="tax_class" name="order_item_tax_class[<?php echo absint( $item_id ); ?>]" title="<?php _e( 'Tax class', 'woocommerce' ); ?>">
<option value="0" <?php selected( 0, $tax_class ) ?>><?php _e( 'N/A', 'woocommerce' ); ?></option>
<optgroup label="<?php _e( 'Taxable', 'woocommerce' ); ?>">
<?php
foreach ( $classes_options as $value => $name ) {
echo '<option value="' . esc_attr( $value ) . '" ' . selected( $value, $tax_class, false ) . '>'. esc_html( $name ) . '</option>';
}
?>
</optgroup>
</select>
</div>
</td>
<?php endif; ?>
<td class="quantity" width="1%">1</td>
<td class="quantity" width="1%">&nbsp;</td>
<td class="line_cost" width="1%">
<div class="view">
<?php echo ( isset( $item['line_total'] ) ) ? wc_price( wc_round_tax_total( $item['line_total'] ) ) : ''; ?>
<?php
echo ( isset( $item['line_total'] ) ) ? wc_price( wc_round_tax_total( $item['line_total'] ) ) : '';
if ( $refunded = $order->get_total_refunded_for_item( $item_id, 'fee' ) ) {
echo '<small class="refunded">-' . wc_price( $refunded ) . '</small>';
}
?>
</div>
<div class="edit" style="display:none">
<label><?php _e( 'Total', 'woocommerce' ); ?>: <input type="text" name="line_total[<?php echo absint( $item_id ); ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php echo ( isset( $item['line_total'] ) ) ? esc_attr( wc_format_localized_price( $item['line_total'] ) ) : ''; ?>" class="line_total wc_input_price" /></label>
<div class="edit" style="display: none;">
<input type="text" name="line_total[<?php echo absint( $item_id ); ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php echo ( isset( $item['line_total'] ) ) ? esc_attr( wc_format_localized_price( $item['line_total'] ) ) : ''; ?>" class="line_total wc_input_price" />
</div>
<div class="refund" style="display: none;">
<input type="text" name="refund_line_total[<?php echo absint( $item_id ); ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" class="refund_line_total wc_input_price" />
</div>
</td>
<?php if ( 'yes' == get_option( 'woocommerce_calc_taxes' ) ) : ?>
<?php
if ( ! $legacy_order && 'yes' == get_option( 'woocommerce_calc_taxes' ) ) :
$line_tax_data = isset( $item['line_tax_data'] ) ? $item['line_tax_data'] : '';
$tax_data = maybe_unserialize( $line_tax_data );
foreach ( $order_taxes as $tax_item ) :
$tax_item_id = $tax_item['rate_id'];
$tax_item_total = isset( $tax_data['total'][ $tax_item_id ] ) ? $tax_data['total'][ $tax_item_id ] : '';
?>
<td class="line_tax" width="1%">
<div class="view">
<?php echo ( isset( $item['line_tax'] ) ) ? wc_price( wc_round_tax_total( $item['line_tax'] ) ) : ''; ?>
<?php
echo ( '' != $tax_item_total ) ? wc_price( wc_round_tax_total( $tax_item_total ) ) : '&ndash;';
if ( $refunded = $order->get_tax_refunded_for_item( $item_id, $tax_item_id, 'fee' ) ) {
echo '<small class="refunded">-' . wc_price( $refunded ) . '</small>';
}
?>
</div>
<div class="edit" style="display:none">
<input type="text" name="line_tax[<?php echo absint( $item_id ); ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php echo ( isset( $item['line_tax'] ) ) ? esc_attr( wc_format_localized_price( $item['line_tax'] ) ) : ''; ?>" class="line_tax wc_input_price" />
<div class="edit" style="display: none;">
<input type="text" name="line_tax[<?php echo absint( $item_id ); ?>][<?php echo absint( $tax_item_id ); ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php echo ( isset( $tax_item_total ) ) ? esc_attr( wc_format_localized_price( $tax_item_total ) ) : ''; ?>" class="line_tax wc_input_price" />
</div>
<div class="refund" style="display: none;">
<input type="text" name="refund_line_tax[<?php echo absint( $item_id ); ?>][<?php echo absint( $tax_item_id ); ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" class="refund_line_tax wc_input_price" data-tax_id="<?php echo absint( $tax_item_id ); ?>" />
</div>
</td>
<?php
endforeach;
endif;
?>
<td class="wc-order-edit-line-item">
<?php if ( $can_be_edited ) : ?>
<div class="wc-order-edit-line-item-actions">
<a class="edit-order-item" href="#"></a><a class="delete-order-item" href="#"></a>
</div>
<?php endif; ?>
<td>
<a class="edit_order_item" href="#"><img src="<?php echo WC()->plugin_url(); ?>/assets/images/icons/edit.png" alt="<?php _e( 'Edit', 'woocommerce' ) ?>" width="14" /></a>
</td>
</tr>

View File

@ -3,7 +3,6 @@ if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
?>
<tr class="item <?php echo apply_filters( 'woocommerce_admin_html_order_item_class', ( ! empty( $class ) ? $class : '' ), $item ); ?>" data-order_item_id="<?php echo $item_id; ?>">
<td class="check-column"><input type="checkbox" /></td>
<td class="thumb">
@ -44,6 +43,7 @@ if ( ! defined( 'ABSPATH' ) ) {
<?php endif; ?>
<input type="hidden" class="order_item_id" name="order_item_id[]" value="<?php echo esc_attr( $item_id ); ?>" />
<input type="hidden" name="order_item_tax_class[<?php echo absint( $item_id ); ?>]" value="<?php echo isset( $item['tax_class'] ) ? esc_attr( $item['tax_class'] ) : ''; ?>" />
<div class="view">
<?php
@ -96,7 +96,7 @@ if ( ! defined( 'ABSPATH' ) ) {
}
?>
</div>
<div class="edit" style="display:none">
<div class="edit" style="display: none;">
<table class="meta" cellspacing="0">
<tbody class="meta_items">
<?php
@ -148,43 +148,22 @@ if ( ! defined( 'ABSPATH' ) ) {
<?php do_action( 'woocommerce_admin_order_item_values', $_product, $item, absint( $item_id ) ); ?>
<?php if ( 'yes' == get_option( 'woocommerce_calc_taxes' ) ) :
$tax_classes = array_filter( array_map( 'trim', explode( "\n", get_option('woocommerce_tax_classes' ) ) ) );
$classes_options = array();
$classes_options[''] = __( 'Standard', 'woocommerce' );
if ( $tax_classes ) {
foreach ( $tax_classes as $class ) {
$classes_options[ sanitize_title( $class ) ] = $class;
}
}
?>
<td class="tax_class" width="1%">
<div class="view">
<?php
$item_value = isset( $item['tax_class'] ) ? sanitize_title( $item['tax_class'] ) : '';
echo $classes_options[ $item_value ];
?>
</div>
<div class="edit" style="display:none">
<select class="tax_class" name="order_item_tax_class[<?php echo absint( $item_id ); ?>]" title="<?php _e( 'Tax class', 'woocommerce' ); ?>">
<?php
$item_value = isset( $item['tax_class'] ) ? sanitize_title( $item['tax_class'] ) : '';
foreach ( $classes_options as $value => $name )
echo '<option value="' . esc_attr( $value ) . '" ' . selected( $value, $item_value, false ) . '>' . esc_html( $name ) . '</option>';
?>
</select>
</div>
</td>
<?php endif; ?>
<td class="quantity" width="1%">
<div class="view">
<?php echo ( isset( $item['qty'] ) ) ? esc_html( $item['qty'] ) : ''; ?>
<?php
echo ( isset( $item['qty'] ) ) ? esc_html( $item['qty'] ) : '';
if ( $refunded_qty = $order->get_qty_refunded_for_item( $item_id ) ) {
echo '<small class="refunded">-' . $refunded_qty . '</small>';
}
?>
</div>
<div class="edit" style="display:none">
<input type="number" step="<?php echo apply_filters( 'woocommerce_quantity_input_step', '1', $_product ); ?>" min="0" autocomplete="off" name="order_item_qty[<?php echo absint( $item_id ); ?>]" placeholder="0" value="<?php echo esc_attr( $item['qty'] ); ?>" size="4" class="quantity" />
<div class="edit" style="display: none;">
<?php $item_qty = esc_attr( $item['qty'] ); ?>
<input type="number" step="<?php echo apply_filters( 'woocommerce_quantity_input_step', '1', $_product ); ?>" min="0" autocomplete="off" name="order_item_qty[<?php echo absint( $item_id ); ?>]" placeholder="0" value="<?php echo $item_qty; ?>" data-qty="<?php echo $item_qty; ?>" size="4" class="quantity" />
</div>
<div class="refund" style="display: none;">
<input type="number" step="<?php echo apply_filters( 'woocommerce_quantity_input_step', '1', $_product ); ?>" min="0" max="<?php echo $item['qty']; ?>" autocomplete="off" name="refund_order_item_qty[<?php echo absint( $item_id ); ?>]" placeholder="0" size="4" class="refund_order_item_qty" />
</div>
</td>
@ -198,40 +177,78 @@ if ( ! defined( 'ABSPATH' ) ) {
echo wc_price( $item['line_total'] );
}
if ( $refunded = $order->get_total_refunded_for_item( $item_id ) ) {
echo '<small class="refunded">-' . wc_price( $refunded ) . '</small>';
}
?>
</div>
<div class="edit" style="display:none">
<span class="subtotal"><label><?php _e( 'Subtotal', 'woocommerce' ); ?>: <a class="tips" data-tip="<?php _e( 'Before pre-tax discounts.', 'woocommerce' ); ?>" href="#">[?]</a> <input type="text" name="line_subtotal[<?php echo absint( $item_id ); ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php echo ( isset( $item['line_subtotal'] ) ) ? esc_attr( wc_format_localized_price( $item['line_subtotal'] ) ) : ''; ?>" class="line_subtotal wc_input_price" /></label></span>
<div class="edit" style="display: none;">
<div class="split-input">
<?php $item_total = ( isset( $item['line_total'] ) ) ? esc_attr( wc_format_localized_price( $item['line_total'] ) ) : ''; ?>
<input type="text" name="line_total[<?php echo absint( $item_id ); ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php echo $item_total; ?>" class="line_total wc_input_price tips" data-tip="<?php _e( 'After pre-tax discounts.', 'woocommerce' ); ?>" data-total="<?php echo $item_total; ?>" />
<label><?php _e( 'Total', 'woocommerce' ); ?>: <a class="tips" data-tip="<?php _e( 'After pre-tax discounts.', 'woocommerce' ); ?>" href="#">[?]</a> <input type="text" name="line_total[<?php echo absint( $item_id ); ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php echo ( isset( $item['line_total'] ) ) ? esc_attr( wc_format_localized_price( $item['line_total'] ) ) : ''; ?>" class="line_total wc_input_price" /></label>
<?php $item_subtotal = ( isset( $item['line_subtotal'] ) ) ? esc_attr( wc_format_localized_price( $item['line_subtotal'] ) ) : ''; ?>
<input type="text" name="line_subtotal[<?php echo absint( $item_id ); ?>]" value="<?php echo $item_subtotal; ?>" class="line_subtotal wc_input_price tips" data-tip="<?php _e( 'Before pre-tax discounts.', 'woocommerce' ); ?>" data-subtotal="<?php echo $item_subtotal; ?>" />
</div>
</div>
<div class="refund" style="display: none;">
<input type="text" name="refund_line_total[<?php echo absint( $item_id ); ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" class="refund_line_total wc_input_price" />
</div>
</td>
<?php if ( 'yes' == get_option( 'woocommerce_calc_taxes' ) ) : ?>
<?php
if ( ! $legacy_order && 'yes' == get_option( 'woocommerce_calc_taxes' ) ) :
$line_tax_data = isset( $item['line_tax_data'] ) ? $item['line_tax_data'] : '';
$tax_data = maybe_unserialize( $line_tax_data );
foreach ( $order_taxes as $tax_item ) :
$tax_item_id = $tax_item['rate_id'];
$tax_item_total = isset( $tax_data['total'][ $tax_item_id ] ) ? $tax_data['total'][ $tax_item_id ] : '';
$tax_item_subtotal = isset( $tax_data['subtotal'][ $tax_item_id ] ) ? $tax_data['subtotal'][ $tax_item_id ] : '';
?>
<td class="line_tax" width="1%">
<div class="view">
<?php
if ( isset( $item['line_tax'] ) ) {
if ( isset( $item['line_subtotal_tax'] ) && $item['line_subtotal_tax'] != $item['line_tax'] ) {
echo '<del>' . wc_price( wc_round_tax_total( $item['line_subtotal_tax'] ) ) . '</del> ';
if ( '' != $tax_item_total ) {
if ( isset( $tax_item_subtotal ) && $tax_item_subtotal != $tax_item_total ) {
echo '<del>' . wc_price( wc_round_tax_total( $tax_item_subtotal ) ) . '</del> ';
}
echo wc_price( wc_round_tax_total( $item['line_tax'] ) );
echo wc_price( wc_round_tax_total( $tax_item_total ) );
} else {
echo '&ndash;';
}
if ( $refunded = $order->get_tax_refunded_for_item( $item_id, $tax_item_id ) ) {
echo '<small class="refunded">-' . wc_price( $refunded ) . '</small>';
}
?>
</div>
<div class="edit" style="display:none">
<span class="subtotal"><input type="text" name="line_subtotal_tax[<?php echo absint( $item_id ); ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php echo ( isset( $item['line_subtotal_tax'] ) ) ? esc_attr( wc_format_localized_price( $item['line_subtotal_tax'] ) ) : ''; ?>" class="line_subtotal_tax wc_input_price" /></span>
<div class="edit" style="display: none;">
<div class="split-input">
<?php $item_total_tax = ( isset( $tax_item_total ) ) ? esc_attr( wc_format_localized_price( $tax_item_total ) ) : ''; ?>
<input type="text" name="line_tax[<?php echo absint( $item_id ); ?>][<?php echo absint( $tax_item_id ); ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php echo $item_total_tax; ?>" class="line_tax wc_input_price tips" data-tip="<?php _e( 'After pre-tax discounts.', 'woocommerce' ); ?>" data-total_tax="<?php echo $item_total_tax; ?>" />
<input type="text" name="line_tax[<?php echo absint( $item_id ); ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php echo ( isset( $item['line_tax'] ) ) ? esc_attr( wc_format_localized_price( $item['line_tax'] ) ) : ''; ?>" class="line_tax wc_input_price" />
<?php $item_subtotal_tax = ( isset( $tax_item_subtotal ) ) ? esc_attr( wc_format_localized_price( $tax_item_subtotal ) ) : ''; ?>
<input type="text" name="line_subtotal_tax[<?php echo absint( $item_id ); ?>][<?php echo absint( $tax_item_id ); ?>]" value="<?php echo $item_subtotal_tax; ?>" class="line_subtotal_tax wc_input_price tips" data-tip="<?php _e( 'Before pre-tax discounts.', 'woocommerce' ); ?>"data-subtotal_tax="<?php echo $item_subtotal_tax; ?>" />
</div>
</div>
<div class="refund" style="display: none;">
<input type="text" name="refund_line_tax[<?php echo absint( $item_id ); ?>][<?php echo absint( $tax_item_id ); ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" class="refund_line_tax wc_input_price" data-tax_id="<?php echo absint( $tax_item_id ); ?>" />
</div>
</td>
<?php
endforeach;
endif;
?>
<td class="wc-order-edit-line-item">
<?php if ( $can_be_edited ) : ?>
<div class="wc-order-edit-line-item-actions">
<a class="edit-order-item" href="#"></a><a class="delete-order-item" href="#"></a>
</div>
<?php endif; ?>
<td>
<a class="edit_order_item" href="#"><img src="<?php echo WC()->plugin_url(); ?>/assets/images/icons/edit.png" alt="<?php _e( 'Edit', 'woocommerce' ); ?>" width="14" /></a>
</td>
</tr>

View File

@ -0,0 +1,328 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
// Get the payment gateway
$payment_gateway = wc_get_payment_gateway_by_order( $order );
// Get line items
$line_items = $order->get_items( apply_filters( 'woocommerce_admin_order_item_types', 'line_item' ) );
// Check if order can be edited
$can_be_edited = in_array( $order->get_status(), apply_filters( 'wc_order_can_be_edited', array( 'pending', 'on-hold' ) ) );
if ( 'yes' == get_option( 'woocommerce_calc_taxes' ) ) {
$order_taxes = $order->get_taxes();
$tax_classes = array_filter( array_map( 'trim', explode( "\n", get_option( 'woocommerce_tax_classes' ) ) ) );
$classes_options = array();
$classes_options[''] = __( 'Standard', 'woocommerce' );
if ( $tax_classes ) {
foreach ( $tax_classes as $class ) {
$classes_options[ sanitize_title( $class ) ] = $class;
}
}
// Older orders won't have line taxes so we need to handle them differently :(
$check_item = current( $line_items );
$tax_data = maybe_unserialize( isset( $check_item['line_tax_data'] ) ? $check_item['line_tax_data'] : '' );
$legacy_order = ! empty( $order_taxes ) && empty( $tax_data ) && ! is_array( $tax_data );
$show_tax_columns = ! $legacy_order || sizeof( $order_taxes ) === 1;
}
?>
<div class="woocommerce_order_items_wrapper wc-order-items-editable">
<table cellpadding="0" cellspacing="0" class="woocommerce_order_items">
<thead>
<tr>
<th><input type="checkbox" class="check-column" /></th>
<th class="item" colspan="2"><?php _e( 'Item', 'woocommerce' ); ?></th>
<?php do_action( 'woocommerce_admin_order_item_headers' ); ?>
<th class="quantity"><?php _e( 'Qty', 'woocommerce' ); ?></th>
<th class="line_cost"><?php _e( 'Total', 'woocommerce' ); ?></th>
<?php
if ( ! $legacy_order && 'yes' == get_option( 'woocommerce_calc_taxes' ) ) :
foreach ( $order_taxes as $tax_id => $tax_item ) :
$tax_class = wc_get_tax_class_by_tax_id( $tax_item['rate_id'] );
$tax_class_name = isset( $classes_options[ $tax_class ] ) ? $classes_options[ $tax_class ] : __( 'Tax', 'woocommerce' );
$column_label = ! empty( $tax_item['label'] ) ? $tax_item['label'] : __( 'Tax', 'woocommerce' );
?>
<th class="line_tax tips" data-tip="<?php
echo esc_attr( $tax_item['name'] . ' (' . $tax_class_name . ')' );
?>">
<?php echo esc_attr( $column_label ); ?>
<input type="hidden" class="order-tax-id" name="order_taxes[<?php echo $tax_id; ?>]" value="<?php echo esc_attr( $tax_item['rate_id'] ); ?>">
<a class="delete-order-tax" href="#" data-rate_id="<?php echo $tax_id; ?>"></a>
</th>
<?php
endforeach;
endif;
?>
<th class="wc-order-edit-line-item" width="1%">&nbsp;</th>
</tr>
</thead>
<tbody id="order_line_items">
<?php
foreach ( $line_items as $item_id => $item ) {
$_product = $order->get_product_from_item( $item );
$item_meta = $order->get_item_meta( $item_id );
include( 'html-order-item.php' );
do_action( 'woocommerce_order_item_' . $item['type'] . '_html', $item_id, $item );
}
?>
</tbody>
<tbody id="order_shipping_line_items">
<?php
$order_items = $order->get_items( 'shipping' );
$shipping_methods = WC()->shipping() ? WC()->shipping->load_shipping_methods() : array();
foreach ( $order_items as $item_id => $item ) {
include( 'html-order-shipping.php' );
}
?>
</tbody>
<tbody id="order_fee_line_items">
<?php
$order_items = $order->get_items( 'fee' );
foreach ( $order_items as $item_id => $item ) {
include( 'html-order-fee.php' );
}
?>
</tbody>
<tbody id="order_refunds">
<?php
if ( $refunds = $order->get_refunds() ) {
foreach ( $refunds as $refund ) {
include( 'html-order-refund.php' );
}
}
?>
</tbody>
</table>
</div>
<div class="wc-order-data-row wc-order-totals-items wc-order-items-editable">
<?php
$coupons = $order->get_items( array( 'coupon' ) );
if ( $coupons ) {
?>
<div class="wc-used-coupons">
<ul class="wc_coupon_list"><?php
foreach ( $coupons as $item_id => $item ) {
$post_id = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM {$wpdb->posts} WHERE post_title = %s AND post_type = 'shop_coupon' AND post_status = 'publish' LIMIT 1;", $item['name'] ) );
$link = $post_id ? add_query_arg( array( 'post' => $post_id, 'action' => 'edit' ), admin_url( 'post.php' ) ) : add_query_arg( array( 's' => $item['name'], 'post_status' => 'all', 'post_type' => 'shop_coupon' ), admin_url( 'edit.php' ) );
echo '<li class="tips code" data-tip="' . esc_attr( wc_price( $item['discount_amount'] ) ) . '"><a href="' . esc_url( $link ) . '"><span>' . esc_html( $item['name'] ). '</span></a></li>';
}
?></ul>
</div>
<?php
}
?>
<table class="wc-order-totals">
<tr>
<td class="label"><?php _e( 'Shipping', 'woocommerce' ); ?> <span class="tips" data-tip="<?php _e( 'This is the shipping and handling total costs for the order.', 'woocommerce' ); ?>">[?]</span>:</td>
<td class="total"><?php echo wc_price( $order->get_total_shipping() ); ?></td>
<td width="1%"></td>
</tr>
<?php if ( 'yes' == get_option( 'woocommerce_calc_taxes' ) ) : ?>
<?php foreach ( $order->get_tax_totals() as $code => $tax ) : ?>
<tr>
<td class="label"><?php echo $tax->label; ?>:</td>
<td class="total"><?php echo $tax->formatted_amount; ?></td>
<td width="1%"></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
<tr>
<td class="label"><?php _e( 'Order Discount', 'woocommerce' ); ?> <span class="tips" data-tip="<?php _e( 'This is the total discount applied after tax.', 'woocommerce' ); ?>">[?]</span>:</td>
<td class="total">
<div class="view"><?php echo wc_price( $order->get_total_discount() ); ?></div>
<div class="edit" style="display: none;">
<input type="text" class="wc_input_price" id="_order_discount" name="_order_discount" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php echo ( isset( $data['_order_discount'][0] ) ) ? esc_attr( wc_format_localized_price( $data['_order_discount'][0] ) ) : ''; ?>" />
<div class="clear"></div>
</div>
</td>
<td><?php if ( $can_be_edited ) : ?><div class="wc-order-edit-line-item-actions"><a class="edit-order-item" href="#"></a></div><?php endif; ?></td>
</tr>
<tr>
<td class="label"><?php _e( 'Order Total', 'woocommerce' ); ?>:</td>
<td class="total">
<div class="view"><?php echo wc_price( $order->get_total() ); ?></div>
<div class="edit" style="display: none;">
<input type="text" class="wc_input_price" id="_order_total" name="_order_total" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php echo ( isset( $data['_order_total'][0] ) ) ? esc_attr( wc_format_localized_price( $data['_order_total'][0] ) ) : ''; ?>" />
<div class="clear"></div>
</div>
</td>
<td><?php if ( $can_be_edited ) : ?><div class="wc-order-edit-line-item-actions"><a class="edit-order-item" href="#"></a></div><?php endif; ?></td>
</tr>
<tr>
<td class="label refunded-total"><?php _e( 'Refunded', 'woocommerce' ); ?>:</td>
<td class="total refunded-total">-<?php echo wc_price( $order->get_total_refunded() ); ?></td>
<td width="1%"></td>
</tr>
</table>
<div class="clear"></div>
</div>
<div class="wc-order-data-row wc-order-bulk-actions">
<p class="bulk-actions">
<select>
<option value=""><?php _e( 'Actions', 'woocommerce' ); ?></option>
<?php if ( $can_be_edited ) : ?>
<optgroup label="<?php _e( 'Edit', 'woocommerce' ); ?>">
<option value="delete"><?php _e( 'Delete selected line item(s)', 'woocommerce' ); ?></option>
</optgroup>
<?php endif; ?>
<optgroup label="<?php _e( 'Stock Actions', 'woocommerce' ); ?>">
<option value="reduce_stock"><?php _e( 'Reduce line item stock', 'woocommerce' ); ?></option>
<option value="increase_stock"><?php _e( 'Increase line item stock', 'woocommerce' ); ?></option>
</optgroup>
</select>
<button type="button" class="button do_bulk_action wc-reload" title="<?php _e( 'Apply', 'woocommerce' ); ?>"><span><?php _e( 'Apply', 'woocommerce' ); ?></span></button>
</p>
<p class="add-items">
<?php if ( $can_be_edited ) : ?>
<button type="button" class="button add-line-item"><?php _e( 'Add line item(s)', 'woocommerce' ); ?></button>
<?php endif; ?>
<?php if ( 'yes' == get_option( 'woocommerce_calc_taxes' ) && $can_be_edited ) : ?>
<button type="button" class="button add-order-tax"><?php _e( 'Add Tax', 'woocommerce' ); ?></button>
<?php endif; ?>
<button type="button" class="button refund-items"><?php _e( 'Refund', 'woocommerce' ); ?></button>
<?php if ( $can_be_edited ) : ?>
<button type="button" class="button button-primary calculate-tax-action"><?php _e( 'Calculate Taxes', 'woocommerce' ); ?></button>
<button type="button" class="button button-primary calculate-action"><?php _e( 'Calculate Total', 'woocommerce' ); ?></button>
<?php endif; ?>
</p>
</div>
<div class="wc-order-data-row wc-order-add-item" style="display:none;">
<button type="button" class="button add-order-item"><?php _e( 'Add product(s)', 'woocommerce' ); ?></button>
<button type="button" class="button add-order-fee"><?php _e( 'Add fee', 'woocommerce' ); ?></button>
<button type="button" class="button add-order-shipping"><?php _e( 'Add shipping cost', 'woocommerce' ); ?></button>
<button type="button" class="button cancel-action"><?php _e( 'Cancel', 'woocommerce' ); ?></button>
<button type="button" class="button button-primary save-action"><?php _e( 'Save', 'woocommerce' ); ?></button>
</div>
<div class="wc-order-data-row wc-order-refund-items" style="display: none;">
<table class="wc-order-totals">
<tr>
<td class="label"><label for="restock_refunded_items"><?php _e( 'Restock refunded items', 'woocommerce' ); ?>:</label></td>
<td class="total"><input type="checkbox" id="restock_refunded_items" name="restock_refunded_items" checked="checked" /></td>
</tr>
<tr>
<td class="label"><?php _e( 'Amount already refunded', 'woocommerce' ); ?>:</td>
<td class="total">-<?php echo wc_price( $order->get_total_refunded() ); ?></td>
</tr>
<tr>
<td class="label"><?php _e( 'Total available to refund', 'woocommerce' ); ?>:</td>
<td class="total"><?php echo wc_price( $order->get_total() - $order->get_total_refunded() ); ?></td>
</tr>
<tr>
<td class="label"><label for="refund_amount"><?php _e( 'Refund amount', 'woocommerce' ); ?>:</label></td>
<td class="total">
<input type="text" class="text" id="refund_amount" name="refund_amount" class="wc_input_price" />
<div class="clear"></div>
</td>
</tr>
<tr>
<td class="label"><label for="refund_reason"><?php _e( 'Reason for refund (optional)', 'woocommerce' ); ?>:</label></td>
<td class="total">
<input type="text" class="text" id="refund_reason" name="refund_reason" />
<div class="clear"></div>
</td>
</tr>
</table>
<div class="clear"></div>
<div class="refund-actions">
<?php if ( false !== $payment_gateway && $payment_gateway->supports( 'refunds' ) ) : ?>
<button type="button" class="button button-primary do-api-refund"><?php printf( _x( 'Refund %s via %s', 'Refund $amount', 'woocommerce' ), '<span class="wc-order-refund-amount">' . wc_price( 0 ) . '</span>', $order->payment_method_title ); ?></button>
<?php endif; ?>
<button type="button" class="button button-primary do-manual-refund"><?php _e( 'Refund manually', 'woocommerce' ); ?></button>
<button type="button" class="button cancel-action"><?php _e( 'Cancel', 'woocommerce' ); ?></button>
<div class="clear"></div>
</div>
</div>
<script type="text/template" id="wc-modal-add-products">
<div class="wc-backbone-modal">
<div class="wc-backbone-modal-content">
<section class="wc-backbone-modal-main" role="main">
<header>
<h1><?php echo __( 'Add products', 'woocommerce' ); ?></h1>
</header>
<article>
<form action="" method="post">
<select id="add_item_id" class="ajax_chosen_select_products_and_variations" multiple="multiple" data-placeholder="<?php _e( 'Search for a product&hellip;', 'woocommerce' ); ?>" style="width: 96%;"></select>
</form>
</article>
<footer>
<div class="inner">
<button id="btn-cancel" class="button button-large"><?php echo __( 'Cancel' , 'woocommerce' ); ?></button>
<button id="btn-ok" class="button button-primary button-large"><?php echo __( 'Add' , 'woocommerce' ); ?></button>
</div>
</footer>
</section>
</div>
</div>
<div class="wc-backbone-modal-backdrop">&nbsp;</div>
</script>
<script type="text/template" id="wc-modal-add-tax">
<div class="wc-backbone-modal">
<div class="wc-backbone-modal-content">
<section class="wc-backbone-modal-main" role="main">
<header>
<h1><?php _e( 'Add tax', 'woocommerce' ); ?></h1>
</header>
<article>
<form action="" method="post">
<table class="widefat">
<thead>
<tr>
<th>&nbsp;</th>
<th><?php _e( 'Rate name', 'woocommerce' ); ?></th>
<th><?php _e( 'Tax class', 'woocommerce' ); ?></th>
<th><?php _e( 'Rate code', 'woocommerce' ); ?></th>
<th><?php _e( 'Rate %', 'woocommerce' ); ?></th>
</tr>
</thead>
<?php
$rates = $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}woocommerce_tax_rates ORDER BY tax_rate_name LIMIT 100" );
foreach ( $rates as $rate ) {
echo '
<tr>
<td><input type="radio" id="add_order_tax_' . absint( $rate->tax_rate_id ) . '" name="add_order_tax" value="' . absint( $rate->tax_rate_id ) . '" /></td>
<td><label for="add_order_tax_' . absint( $rate->tax_rate_id ) . '">' . WC_Tax::get_rate_label( $rate ) . '</label></td>
<td>' . ( isset( $classes_options[ $rate->tax_rate_class ] ) ? $classes_options[ $rate->tax_rate_class ] : '-' ) . '</td>
<td>' . WC_Tax::get_rate_code( $rate ) . '</td>
<td>' . WC_Tax::get_rate_percent( $rate ) . '</td>
</tr>
';
}
?>
</table>
<?php if ( absint( $wpdb->get_var( "SELECT COUNT(tax_rate_id) FROM {$wpdb->prefix}woocommerce_tax_rates;" ) ) > 100 ) : ?>
<p>
<label for="manual_tax_rate_id"><?php _e( 'Or, enter tax rate ID:', 'woocommerce' ); ?></label><br/>
<input type="number" name="manual_tax_rate_id" id="manual_tax_rate_id" step="1" placeholder="<?php _e( 'Optional', 'woocommerce' ); ?>" />
</p>
<?php endif; ?>
</form>
</article>
<footer>
<div class="inner">
<button id="btn-cancel" class="button button-large"><?php echo __( 'Cancel' , 'woocommerce' ); ?></button>
<button id="btn-ok" class="button button-primary button-large"><?php echo __( 'Add' , 'woocommerce' ); ?></button>
</div>
</footer>
</section>
</div>
</div>
<div class="wc-backbone-modal-backdrop">&nbsp;</div>
</script>

View File

@ -0,0 +1,38 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
?>
<tr class="refund <?php echo ( ! empty( $class ) ) ? $class : ''; ?>" data-order_refund_id="<?php echo $refund->id; ?>">
<td class="check-column"></td>
<td class="thumb"><div></div></td>
<td class="name">
<?php _e( 'Refund', 'woocommerce' ); ?> - <?php echo date_i18n( get_option( 'date_format' ) . ', ' . get_option( 'time_format' ), strtotime( $refund->post_date ) ); ?>
<?php if ( $refund->get_refund_reason() ) : ?>
<p class="description"><?php echo esc_html( $refund->get_refund_reason() ); ?></p>
<?php endif; ?>
<input type="hidden" class="order_refund_id" name="order_refund_id[]" value="<?php echo esc_attr( $refund->id ); ?>" />
</td>
<td class="quantity" width="1%">&nbsp;</td>
<td class="line_cost" width="1%">
<div class="view">
<?php echo wc_price( '-' . $refund->get_refund_amount() ); ?>
</div>
</td>
<?php if ( ! $legacy_order && 'yes' == get_option( 'woocommerce_calc_taxes' ) ) : for ( $i = 0; $i < count( $order_taxes ); $i++ ) : ?>
<td class="line_tax" width="1%"></td>
<?php endfor; endif; ?>
<td class="wc-order-edit-line-item">
<div class="wc-order-edit-line-item-actions">
<a class="delete_refund" href="#"></a>
</div>
</td>
</tr>

View File

@ -1,44 +1,110 @@
<?php
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
?>
<div class="total_row shipping_row" data-order_item_id="<?php echo $item_id; ?>">
<p class="wide">
<input type="text" name="shipping_method_title[<?php echo $item_id ? $item_id : 'new][]'; ?>]" placeholder="<?php _e( 'Label', 'woocommerce' ); ?>" value="<?php echo esc_attr( $shipping_title ); ?>" class="first" />
<input type="hidden" name="shipping_method_id[<?php echo $item_id ? $item_id : 'new][]'; ?>]" value="<?php echo esc_attr( $item_id ); ?>" />
</p>
<p class="first">
<select name="shipping_method[<?php echo $item_id ? $item_id : 'new][]'; ?>]" class="first">
<tr class="shipping <?php echo ( ! empty( $class ) ) ? $class : ''; ?>" data-order_item_id="<?php echo $item_id; ?>">
<td class="check-column"><input type="checkbox" /></td>
<td class="thumb"><div></div></td>
<td class="name">
<div class="view">
<?php echo ! empty( $item['name'] ) ? esc_html( $item['name'] ) : __( 'Shipping', 'woocommerce' ); ?>
</div>
<div class="edit" style="display: none;">
<input type="text" placeholder="<?php _e( 'Shipping Name', 'woocommerce' ); ?>" name="shipping_method_title[<?php echo $item_id; ?>]" value="<?php echo ( isset( $item['name'] ) ) ? esc_attr( $item['name'] ) : ''; ?>" />
<select name="shipping_method[<?php echo $item_id; ?>]">
<optgroup label="<?php _e( 'Shipping Method', 'woocommerce' ); ?>">
<option value=""><?php _e( 'N/A', 'woocommerce' ); ?></option>
<?php
$found_method = false;
foreach ( $shipping_methods as $method ) {
$method_id = isset( $item['method_id'] ) ? $item['method_id'] : '';
$current_method = ( 0 === strpos( $method_id, $method->id ) ) ? $method_id : $method->id;
if ( strpos( $chosen_method, $method->id ) === 0 )
$value = $chosen_method;
else
$value = $method->id;
echo '<option value="' . esc_attr( $current_method ) . '" ' . selected( $method_id == $current_method, true, false ) . '>' . esc_html( $method->get_title() ) . '</option>';
echo '<option value="' . esc_attr( $value ) . '" ' . selected( $chosen_method == $value, true, false ) . '>' . esc_html( $method->get_title() ) . '</option>';
if ( $chosen_method == $value )
if ( $method_id == $current_method ) {
$found_method = true;
}
}
if ( ! $found_method && ! empty( $chosen_method ) ) {
echo '<option value="' . esc_attr( $chosen_method ) . '" selected="selected">' . __( 'Other', 'woocommerce' ) . '</option>';
if ( ! $found_method && ! empty( $method_id ) ) {
echo '<option value="' . esc_attr( $method_id ) . '" selected="selected">' . __( 'Other', 'woocommerce' ) . '</option>';
} else {
echo '<option value="other">' . __( 'Other', 'woocommerce' ) . '</option>';
}
?>
</optgroup>
</select>
</p>
<p class="last">
<input type="text" class="shipping_cost wc_input_price" name="shipping_cost[<?php echo $item_id ? $item_id : 'new][]'; ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php echo esc_attr( wc_format_localized_price( $shipping_cost ) ); ?>" />
</p>
<?php do_action( 'woocommerce_admin_order_totals_after_shipping_item', $item_id ); ?>
<a href="#" class="delete_total_row">&times;</a>
<div class="clear"></div>
</div>
<input type="hidden" name="shipping_method_id[]" value="<?php echo esc_attr( $item_id ); ?>" />
</div>
</td>
<?php do_action( 'woocommerce_admin_order_item_values', null, $item, absint( $item_id ) ); ?>
<td class="quantity" width="1%">&nbsp;</td>
<td class="line_cost" width="1%">
<div class="view">
<?php
echo ( isset( $item['cost'] ) ) ? wc_price( wc_round_tax_total( $item['cost'] ) ) : '';
if ( $refunded = $order->get_total_refunded_for_item( $item_id, 'shipping' ) ) {
echo '<small class="refunded">-' . wc_price( $refunded ) . '</small>';
}
?>
</div>
<div class="edit" style="display: none;">
<input type="text" name="shipping_cost[<?php echo $item_id; ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php echo ( isset( $item['cost'] ) ) ? esc_attr( wc_format_localized_price( $item['cost'] ) ) : ''; ?>" class="line_total wc_input_price" />
</div>
<div class="refund" style="display: none;">
<input type="text" name="refund_line_total[<?php echo absint( $item_id ); ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" class="refund_line_total wc_input_price" />
</div>
</td>
<?php
if ( ! $legacy_order && 'yes' == get_option( 'woocommerce_calc_taxes' ) ) :
$shipping_taxes = isset( $item['taxes'] ) ? $item['taxes'] : '';
$tax_data = maybe_unserialize( $shipping_taxes );
foreach ( $order_taxes as $tax_item ) :
$tax_item_id = $tax_item['rate_id'];
$tax_item_total = isset( $tax_data[ $tax_item_id ] ) ? $tax_data[ $tax_item_id ] : '';
?>
<td class="line_tax" width="1%">
<div class="view">
<?php
echo ( '' != $tax_item_total ) ? wc_price( wc_round_tax_total( $tax_item_total ) ) : '&ndash;';
if ( $refunded = $order->get_tax_refunded_for_item( $item_id, $tax_item_id, 'shipping' ) ) {
echo '<small class="refunded">-' . wc_price( $refunded ) . '</small>';
}
?>
</div>
<div class="edit" style="display: none;">
<input type="text" name="shipping_taxes[<?php echo absint( $item_id ); ?>][<?php echo absint( $tax_item_id ); ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php echo ( isset( $tax_item_total ) ) ? esc_attr( wc_format_localized_price( $tax_item_total ) ) : ''; ?>" class="line_tax wc_input_price" />
</div>
<div class="refund" style="display: none;">
<input type="text" name="refund_line_tax[<?php echo absint( $item_id ); ?>][<?php echo absint( $tax_item_id ); ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" class="refund_line_tax wc_input_price" data-tax_id="<?php echo absint( $tax_item_id ); ?>" />
</div>
</td>
<?php
endforeach;
endif;
?>
<td class="wc-order-edit-line-item">
<?php if ( $can_be_edited ) : ?>
<div class="wc-order-edit-line-item-actions">
<a class="edit-order-item" href="#"></a><a class="delete-order-item" href="#"></a>
</div>
<?php endif; ?>
</td>
</tr>

View File

@ -1,26 +0,0 @@
<?php
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
?>
<div class="total_row tax_row" data-order_item_id="<?php echo $item_id; ?>">
<p class="wide">
<select name="order_taxes_rate_id[<?php echo $item_id ? $item_id : 'new][]'; ?>]">
<optgroup label="<?php _e( 'Tax Rate', 'woocommerce' ); ?>">
<option value=""><?php _e( 'N/A', 'woocommerce' ); ?></option>
<?php foreach( $tax_codes as $tax_id => $tax_code ) : ?>
<option value="<?php echo $tax_id; ?>" <?php selected( $tax_id, isset( $item['rate_id'] ) ? $item['rate_id'] : '' ); ?>><?php echo esc_html( urldecode( $tax_code ) ); ?></option>
<?php endforeach; ?>
</optgroup>
</select>
<input type="hidden" name="order_taxes_id[<?php echo $item_id ? $item_id : 'new][]'; ?>]" value="<?php echo esc_attr( $item_id ); ?>" />
</p>
<p class="first">
<label><?php _e( 'Sales Tax', 'woocommerce' ) ?></label>
<input type="text" class="order_taxes_amount wc_input_price" name="order_taxes_amount[<?php echo $item_id ? $item_id : 'new][]'; ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php if ( isset( $item['tax_amount'] ) ) echo esc_attr( wc_format_localized_price( $item['tax_amount'] ) ); ?>" />
</p>
<p class="last">
<label><?php _e( 'Shipping Tax', 'woocommerce' ) ?></label>
<input type="text" class="order_taxes_shipping_amount wc_input_price" name="order_taxes_shipping_amount[<?php echo $item_id ? $item_id : 'new][]'; ?>]" placeholder="<?php echo wc_format_localized_price( 0 ); ?>" value="<?php if ( isset( $item['shipping_tax_amount'] ) ) echo esc_attr( wc_format_localized_price( $item['shipping_tax_amount'] ) ); ?>" />
</p>
<a href="#" class="delete_total_row">&times;</a>
<div class="clear"></div>
</div>

View File

@ -47,7 +47,8 @@ class WC_Admin_Report {
'limit' => '',
'filter_range' => false,
'nocache' => false,
'debug' => false
'debug' => false,
'order_types' => wc_get_order_types( 'reports' )
);
$args = apply_filters( 'woocommerce_reports_get_order_report_data_args', wp_parse_args( $args, $defaults ) );
@ -128,7 +129,7 @@ class WC_Admin_Report {
$query['join'] = implode( ' ', $joins );
$query['where'] = "
WHERE posts.post_type = 'shop_order'
WHERE posts.post_type IN ( '" . implode( "','", $order_types ) . "' )
AND posts.post_status IN ( 'wc-" . implode( "','wc-", apply_filters( 'woocommerce_reports_order_statuses', array( 'completed', 'processing', 'on-hold' ) ) ) . "')
";

View File

@ -116,7 +116,7 @@ class WC_Report_Customer_List extends WP_List_Table {
WHERE meta.meta_key = '_customer_user'
AND meta.meta_value = $user->ID
AND posts.post_type = 'shop_order'
AND posts.post_type IN ('" . implode( ',', wc_get_order_types( 'reports' ) ) . "')
AND posts.post_status = 'wc-completed'
AND meta2.meta_key = '_order_total'
" );
@ -135,7 +135,7 @@ class WC_Report_Customer_List extends WP_List_Table {
LEFT JOIN {$wpdb->postmeta} AS meta ON posts.ID = meta.post_id
WHERE meta.meta_key = '_customer_user'
AND posts.post_type = 'shop_order'
AND posts.post_type IN ('" . implode( ',', wc_get_order_types( 'order-count' ) ) . "')
AND posts.post_status = 'wc-completed'
AND meta_value = $user->ID
" );
@ -190,7 +190,7 @@ class WC_Report_Customer_List extends WP_List_Table {
$order_ids = get_posts( array(
'posts_per_page' => 1,
'post_type' => 'shop_order',
'post_type' => wc_get_order_types(),
'post_status' => array_keys( wc_get_order_statuses() ),
'meta_query' => array(
array(

View File

@ -29,18 +29,24 @@ class WC_Report_Sales_By_Date extends WC_Admin_Report {
'type' => 'meta',
'function' => 'SUM',
'name' => 'total_shipping'
),
'ID' => array(
'type' => 'post_data',
'function' => 'COUNT',
'name' => 'total_orders'
)
),
'filter_range' => true
) );
$total_sales = $order_totals->total_sales;
$total_shipping = $order_totals->total_shipping;
$total_orders = absint( $order_totals->total_orders );
$total_orders = absint( $this->get_order_report_data( array(
'data' => array(
'ID' => array(
'type' => 'post_data',
'function' => 'COUNT',
'name' => 'total_orders'
)
),
'query_type' => 'get_var',
'filter_range' => true,
'order_types' => wc_get_order_types( 'order-count' )
) ) );
$total_items = absint( $this->get_order_report_data( array(
'data' => array(
'_qty' => array(
@ -51,6 +57,7 @@ class WC_Report_Sales_By_Date extends WC_Admin_Report {
)
),
'query_type' => 'get_var',
'order_types' => wc_get_order_types( 'order-count' ),
'filter_range' => true
) ) );
// Get discount amounts in range
@ -71,6 +78,7 @@ class WC_Report_Sales_By_Date extends WC_Admin_Report {
)
),
'query_type' => 'get_var',
'order_types' => wc_get_order_types( 'order-count' ),
'filter_range' => true
) );

View File

@ -72,6 +72,7 @@ class WC_Report_Sales_By_Product extends WC_Admin_Report {
)
),
'query_type' => 'get_var',
'order_types' => wc_get_order_types( 'order-count' ),
'filter_range' => true
) ) );
@ -224,7 +225,8 @@ class WC_Report_Sales_By_Product extends WC_Admin_Report {
'group_by' => 'product_id',
'limit' => 12,
'query_type' => 'get_results',
'filter_range' => true
'filter_range' => true,
'order_types' => wc_get_order_types( 'order-count' ),
) );
if ( $top_sellers ) {

View File

@ -89,6 +89,11 @@ class WC_Report_Taxes_By_Code extends WC_Admin_Report {
'order_item_type' => 'tax',
'function' => '',
'name' => 'rate_id'
),
'order_id' => array(
'type' => 'order_item',
'function' => '',
'name' => 'order_id'
)
),
'where' => array(
@ -133,8 +138,9 @@ class WC_Report_Taxes_By_Code extends WC_Admin_Report {
'shipping_tax_amount' => 0
);
}
if ( 'shop_order' === get_post_type( $tax_row->order_id ) ) {
$grouped_tax_tows[ $tax_row->rate_id ]->total_orders ++;
}
$grouped_tax_tows[ $tax_row->rate_id ]->tax_amount += wc_round_tax_total( $tax_row->tax_amount );
$grouped_tax_tows[ $tax_row->rate_id ]->shipping_tax_amount += wc_round_tax_total( $tax_row->shipping_tax_amount );
}

View File

@ -107,7 +107,7 @@ class WC_Report_Taxes_By_Date extends WC_Admin_Report {
<thead>
<tr>
<th><?php _e( 'Period', 'woocommerce' ); ?></th>
<th class="total_row"><?php _e( 'Number of orders', 'woocommerce' ); ?></th>
<th class="total_row"><?php _e( 'Orders/refunds', 'woocommerce' ); ?></th>
<th class="total_row"><?php _e( 'Total Sales', 'woocommerce' ); ?> <a class="tips" data-tip="<?php _e("This is the sum of the 'Order Total' field within your orders.", 'woocommerce'); ?>" href="#">[?]</a></th>
<th class="total_row"><?php _e( 'Total Shipping', 'woocommerce' ); ?> <a class="tips" data-tip="<?php _e("This is the sum of the 'Shipping Total' field within your orders.", 'woocommerce'); ?>" href="#">[?]</a></th>
<th class="total_row"><?php _e( 'Total Tax', 'woocommerce' ); ?> <a class="tips" data-tip="<?php esc_attr_e( 'This is the total tax for the rate (shipping tax + product tax).', 'woocommerce' ); ?>" href="#">[?]</a></th>

View File

@ -282,7 +282,7 @@ class WC_Settings_Tax extends WC_Settings_Page {
foreach ( $rates as $rate ) {
?>
<tr>
<tr class="tips" data-tip="<?php echo __( 'Tax rate ID', 'woocommerce' ) . ': ' . $rate->tax_rate_id; ?>">
<td class="sort"><input type="hidden" class="remove_tax_rate" name="remove_tax_rate[<?php echo $rate->tax_rate_id ?>]" value="0" /></td>
<td class="country" width="8%">

View File

@ -17,16 +17,13 @@ if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
*/
function wc_get_screen_ids() {
$wc_screen_id = sanitize_title( __( 'WooCommerce', 'woocommerce' ) );
return apply_filters( 'woocommerce_screen_ids', array(
$screen_ids = array(
'toplevel_page_' . $wc_screen_id,
$wc_screen_id . '_page_wc-reports',
$wc_screen_id . '_page_wc-settings',
$wc_screen_id . '_page_wc-status',
$wc_screen_id . '_page_wc-addons',
'product_page_product_attributes',
'edit-shop_order',
'shop_order',
'edit-product',
'product',
'edit-shop_coupon',
@ -34,7 +31,14 @@ function wc_get_screen_ids() {
'edit-product_cat',
'edit-product_tag',
'edit-product_shipping_class'
) );
);
foreach ( wc_get_order_types() as $type ) {
$screen_ids[] = $type;
$screen_ids[] = 'edit-' . $type;
}
return apply_filters( 'woocommerce_screen_ids', $screen_ids );
}
/**
@ -191,3 +195,198 @@ function woocommerce_compile_less_styles() {
}
}
}
/**
* Save order items
*
* @since 2.2
* @param int $order_id Order ID
* @param array $items Order items to save
* @return void
*/
function wc_save_order_items( $order_id, $items ) {
global $wpdb;
// Order items + fees
$subtotal = 0;
$total = 0;
$taxes = array( 'items' => array(), 'shipping' => array() );
if ( isset( $items['order_item_id'] ) ) {
$get_values = array( 'order_item_id', 'order_item_name', 'order_item_qty', 'line_subtotal', 'line_subtotal_tax', 'line_total', 'line_tax', 'order_item_tax_class' );
foreach ( $get_values as $value ) {
$$value = isset( $items[ $value ] ) ? $items[ $value ] : array();
}
foreach ( $order_item_id as $item_id ) {
$item_id = absint( $item_id );
if ( isset( $order_item_name[ $item_id ] ) ) {
$wpdb->update(
$wpdb->prefix . 'woocommerce_order_items',
array( 'order_item_name' => wc_clean( $order_item_name[ $item_id ] ) ),
array( 'order_item_id' => $item_id ),
array( '%s' ),
array( '%d' )
);
}
if ( isset( $order_item_qty[ $item_id ] ) ) {
wc_update_order_item_meta( $item_id, '_qty', wc_stock_amount( $order_item_qty[ $item_id ] ) );
}
if ( isset( $order_item_tax_class[ $item_id ] ) ) {
wc_update_order_item_meta( $item_id, '_tax_class', wc_clean( $order_item_tax_class[ $item_id ] ) );
}
// Get values. Subtotals might not exist, in which case copy value from total field
$line_total[ $item_id ] = isset( $line_total[ $item_id ] ) ? $line_total[ $item_id ] : 0;
$line_subtotal[ $item_id ] = isset( $line_subtotal[ $item_id ] ) ? $line_subtotal[ $item_id ] : $line_total[ $item_id ];
$line_tax[ $item_id ] = isset( $line_tax[ $item_id ] ) ? $line_tax[ $item_id ] : array();
$line_subtotal_tax[ $item_id ] = isset( $line_subtotal_tax[ $item_id ] ) ? $line_subtotal_tax[ $item_id ] : $line_tax[ $item_id ];
// Update values
wc_update_order_item_meta( $item_id, '_line_subtotal', wc_format_decimal( $line_subtotal[ $item_id ] ) );
wc_update_order_item_meta( $item_id, '_line_total', wc_format_decimal( $line_total[ $item_id ] ) );
wc_update_order_item_meta( $item_id, '_line_subtotal_tax', wc_format_decimal( array_sum( $line_subtotal_tax[ $item_id ] ) ) );
wc_update_order_item_meta( $item_id, '_line_tax', wc_format_decimal( array_sum( $line_tax[ $item_id ] ) ) );
// Save line tax data - Since 2.2
$tax_data_total = array_map( 'wc_format_decimal', $line_tax[ $item_id ] );
$tax_data_subtotal = array_map( 'wc_format_decimal', $line_subtotal_tax[ $item_id ] );
wc_update_order_item_meta( $item_id, '_line_tax_data', array( 'total' => $tax_data_total, 'subtotal' => $tax_data_subtotal ) );
$taxes['items'][] = $tax_data_total;
// Total up
$subtotal += wc_format_decimal( $line_subtotal[ $item_id ] );
$total += wc_format_decimal( $line_total[ $item_id ] );
// Clear meta cache
wp_cache_delete( $item_id, 'order_item_meta' );
}
}
// Save meta
$meta_keys = isset( $items['meta_key'] ) ? $items['meta_key'] : array();
$meta_values = isset( $items['meta_value'] ) ? $items['meta_value'] : array();
foreach ( $meta_keys as $id => $meta_key ) {
$meta_value = ( empty( $meta_values[ $id ] ) && ! is_numeric( $meta_values[ $id ] ) ) ? '' : $meta_values[ $id ];
$wpdb->update(
$wpdb->prefix . 'woocommerce_order_itemmeta',
array(
'meta_key' => wp_unslash( $meta_key ),
'meta_value' => wp_unslash( $meta_value )
),
array( 'meta_id' => $id ),
array( '%s', '%s' ),
array( '%d' )
);
}
// Shipping Rows
$order_shipping = 0;
if ( isset( $items['shipping_method_id'] ) ) {
$get_values = array( 'shipping_method_id', 'shipping_method_title', 'shipping_method', 'shipping_cost', 'shipping_taxes' );
foreach ( $get_values as $value ) {
$$value = isset( $items[ $value ] ) ? $items[ $value ] : array();
}
foreach ( $shipping_method_id as $item_id ) {
$item_id = absint( $item_id );
$method_id = wc_clean( $shipping_method[ $item_id ] );
$method_title = wc_clean( $shipping_method_title[ $item_id ] );
$cost = wc_format_decimal( $shipping_cost[ $item_id ] );
$ship_taxes = isset( $shipping_taxes[ $item_id ] ) ? array_map( 'wc_format_decimal', $shipping_taxes[ $item_id ] ) : array();
$wpdb->update(
$wpdb->prefix . 'woocommerce_order_items',
array( 'order_item_name' => $method_title ),
array( 'order_item_id' => $item_id ),
array( '%s' ),
array( '%d' )
);
wc_update_order_item_meta( $item_id, 'method_id', $method_id );
wc_update_order_item_meta( $item_id, 'cost', $cost );
wc_update_order_item_meta( $item_id, 'taxes', $ship_taxes );
$taxes['shipping'][] = $ship_taxes;
$order_shipping += $cost;
}
}
// Taxes
$order_taxes = isset( $items['order_taxes'] ) ? $items['order_taxes'] : array();
$taxes_items = array();
$taxes_shipping = array();
$total_tax = 0;
$total_shipping_tax = 0;
// Sum items taxes
foreach ( $taxes['items'] as $rates ) {
foreach ( $rates as $id => $value ) {
if ( isset( $taxes_items[ $id ] ) ) {
$taxes_items[ $id ] += $value;
} else {
$taxes_items[ $id ] = $value;
}
}
}
// Sum shipping taxes
foreach ( $taxes['shipping'] as $rates ) {
foreach ( $rates as $id => $value ) {
if ( isset( $taxes_shipping[ $id ] ) ) {
$taxes_shipping[ $id ] += $value;
} else {
$taxes_shipping[ $id ] = $value;
}
}
}
// Update order taxes
foreach ( $order_taxes as $item_id => $rate_id ) {
if ( isset( $taxes_items[ $rate_id ] ) ) {
$_total = wc_format_decimal( $taxes_items[ $rate_id ] );
wc_update_order_item_meta( $item_id, 'tax_amount', $_total );
$total_tax += $_total;
}
if ( isset( $taxes_shipping[ $rate_id ] ) ) {
$_total = wc_format_decimal( $taxes_shipping[ $rate_id ] );
wc_update_order_item_meta( $item_id, 'shipping_tax_amount', $_total );
$total_shipping_tax += $_total;
}
}
// Update order shipping total
update_post_meta( $order_id, '_order_shipping', $order_shipping );
// Update cart discount from item totals
update_post_meta( $order_id, '_cart_discount', $subtotal - $total );
// Update totals
update_post_meta( $order_id, '_order_discount', wc_format_decimal( $items['_order_discount'] ) );
update_post_meta( $order_id, '_order_total', wc_format_decimal( $items['_order_total'] ) );
// Update tax
update_post_meta( $order_id, '_order_tax', wc_format_decimal( $total_tax ) );
update_post_meta( $order_id, '_order_shipping_tax', wc_format_decimal( $total_shipping_tax ) );
// Remove old values
delete_post_meta( $order_id, '_shipping_method' );
delete_post_meta( $order_id, '_shipping_method_title' );
// Set the currency
add_post_meta( $order_id, '_order_currency', get_woocommerce_currency(), true );
}

View File

@ -44,12 +44,17 @@ class WC_AJAX {
'get_customer_details' => false,
'add_order_item' => false,
'add_order_fee' => false,
'add_order_shipping' => false,
'add_order_tax' => false,
'remove_order_item' => false,
'remote_order_tax' => false,
'reduce_order_item_stock' => false,
'increase_order_item_stock' => false,
'add_order_item_meta' => false,
'remove_order_item_meta' => false,
'calc_line_taxes' => false,
'save_order_items' => false,
'load_order_items' => false,
'add_order_note' => false,
'delete_order_note' => false,
'json_search_products' => false,
@ -57,7 +62,9 @@ class WC_AJAX {
'json_search_downloadable_products_and_variations' => false,
'json_search_customers' => false,
'term_ordering' => false,
'product_ordering' => false
'product_ordering' => false,
'refund_line_items' => false,
'delete_refund' => false
);
foreach ( $ajax_events as $ajax_event => $nopriv ) {
@ -937,6 +944,7 @@ class WC_AJAX {
$_product = get_product( $post->ID );
$order = get_order( $order_id );
$order_taxes = $order->get_taxes();
$class = 'new_row';
// Set values
@ -970,6 +978,9 @@ class WC_AJAX {
wc_add_order_item_meta( $item_id, '_line_total', $item['line_total'] );
wc_add_order_item_meta( $item_id, '_line_tax', $item['line_tax'] );
// Since 2.2
wc_add_order_item_meta( $item_id, '_line_tax_data', array( 'total' => array(), 'subtotal' => array() ) );
// Store variation data in meta
if ( $item['variation_data'] && is_array( $item['variation_data'] ) ) {
foreach ( $item['variation_data'] as $key => $value ) {
@ -981,6 +992,7 @@ class WC_AJAX {
}
$item = apply_filters( 'woocommerce_ajax_order_item', $item, $item_id );
$can_be_edited = in_array( $order->get_status(), apply_filters( 'wc_order_can_be_edited', array( 'pending', 'on-hold' ) ) );
include( 'admin/meta-boxes/views/html-order-item.php' );
@ -997,19 +1009,19 @@ class WC_AJAX {
$order_id = absint( $_POST['order_id'] );
$order = get_order( $order_id );
$order_taxes = $order->get_taxes();
$can_be_edited = in_array( $order->get_status(), apply_filters( 'wc_order_can_be_edited', array( 'pending', 'on-hold' ) ) );
$item = array();
// Add line item
$item_id = wc_add_order_item( $order_id, array(
'order_item_name' => '',
'order_item_type' => 'fee'
) );
// Add line item meta
if ( $item_id ) {
wc_add_order_item_meta( $item_id, '_tax_class', '' );
wc_add_order_item_meta( $item_id, '_line_total', '' );
wc_add_order_item_meta( $item_id, '_line_tax', '' );
}
// Add new fee
$fee = new stdClass();
$fee->name = '';
$fee->tax_class = '';
$fee->taxable = $fee->tax_class !== '0';
$fee->amount = '';
$fee->tax = '';
$fee->tax_data = array();
$item_id = $order->add_fee( $fee );
include( 'admin/meta-boxes/views/html-order-fee.php' );
@ -1017,6 +1029,56 @@ class WC_AJAX {
die();
}
/**
* Add order shipping cost via ajax
*/
public static function add_order_shipping() {
check_ajax_referer( 'order-item', 'security' );
$order_id = absint( $_POST['order_id'] );
$order = get_order( $order_id );
$order_taxes = $order->get_taxes();
$shipping_methods = WC()->shipping() ? WC()->shipping->load_shipping_methods() : array();
$can_be_edited = in_array( $order->get_status(), apply_filters( 'wc_order_can_be_edited', array( 'pending', 'on-hold' ) ) );
$item = array();
// Add new shipping
$shipping = new stdClass();
$shipping->label = '';
$shipping->id = '';
$shipping->cost = '';
$shipping->taxes = array();
$item_id = $order->add_shipping( $shipping );
include( 'admin/meta-boxes/views/html-order-shipping.php' );
// Quit out
die();
}
/**
* Add order tax column via ajax
*/
public static function add_order_tax() {
global $wpdb;
check_ajax_referer( 'order-item', 'security' );
$order_id = absint( $_POST['order_id'] );
$rate_id = absint( $_POST['rate_id'] );
$order = new WC_Order( $order_id );
$data = get_post_meta( $order_id );
// Add new tax
$order->add_tax( $rate_id, 0, 0 );
// Return HTML items
include( 'admin/meta-boxes/views/html-order-items.php' );
die();
}
/**
* Remove an order item
*/
@ -1025,6 +1087,10 @@ class WC_AJAX {
$order_item_ids = $_POST['order_item_ids'];
if ( ! is_array( $order_item_ids ) && is_numeric( $order_item_ids ) ) {
$order_item_ids = array( $order_item_ids );
}
if ( sizeof( $order_item_ids ) > 0 ) {
foreach( $order_item_ids as $id ) {
wc_delete_order_item( absint( $id ) );
@ -1034,6 +1100,26 @@ class WC_AJAX {
die();
}
/**
* Remove an order tax
*/
public static function remote_order_tax() {
check_ajax_referer( 'order-item', 'security' );
$order_id = absint( $_POST['order_id'] );
$rate_id = absint( $_POST['rate_id'] );
wc_delete_order_item( $rate_id );
// Return HTML items
$order = new WC_Order( $order_id );
$data = get_post_meta( $order_id );
include( 'admin/meta-boxes/views/html-order-items.php' );
die();
}
/**
* Reduce order item stock
*/
@ -1166,25 +1252,42 @@ class WC_AJAX {
check_ajax_referer( 'calc-totals', 'security' );
$tax = new WC_Tax();
$taxes = $tax_rows = $item_taxes = $shipping_taxes = array();
$order_id = absint( $_POST['order_id'] );
$order = get_order( $order_id );
$items = array();
$country = strtoupper( esc_attr( $_POST['country'] ) );
$state = strtoupper( esc_attr( $_POST['state'] ) );
$postcode = strtoupper( esc_attr( $_POST['postcode'] ) );
$city = sanitize_title( esc_attr( $_POST['city'] ) );
$items = isset( $_POST['items'] ) ? $_POST['items'] : array();
$shipping = $_POST['shipping'];
$item_tax = 0;
$order = get_order( $order_id );
$taxes = array();
$shipping_taxes = array();
// Calculate sales tax first
if ( sizeof( $items ) > 0 ) {
foreach( $items as $item_id => $item ) {
// Parse the jQuery serialized items
parse_str( $_POST['items'], $items );
// Prevent undefined warnings
if ( ! isset( $items['line_tax'] ) ) {
$items['line_tax'] = array();
}
if ( ! isset( $items['line_subtotal_tax'] ) ) {
$items['line_subtotal_tax'] = array();
}
$items['order_taxes'] = array();
// Get items and fees taxes
if ( isset( $items['order_item_id'] ) ) {
$get_values = array( 'order_item_id', 'line_subtotal', 'line_total', 'order_item_tax_class' );
foreach ( $get_values as $value ) {
$$value = isset( $items[ $value ] ) ? $items[ $value ] : array();
}
foreach ( $order_item_id as $item_id ) {
$item_id = absint( $item_id );
$line_subtotal = isset( $item['line_subtotal'] ) ? wc_format_decimal( $item['line_subtotal'] ) : 0;
$line_total = wc_format_decimal( $item['line_total'] );
$tax_class = sanitize_text_field( $item['tax_class'] );
$line_total[ $item_id ] = isset( $line_total[ $item_id ] ) ? wc_format_decimal( $line_total[ $item_id ] ) : 0;
$line_subtotal[ $item_id ] = isset( $line_subtotal[ $item_id ] ) ? wc_format_decimal( $line_subtotal[ $item_id ] ) : $line_total[ $item_id ];
$order_item_tax_class[ $item_id ] = isset( $order_item_tax_class[ $item_id ] ) ? sanitize_text_field( $order_item_tax_class[ $item_id ] ) : '';
$product_id = $order->get_item_meta( $item_id, '_product_id', true );
// Get product details
@ -1195,26 +1298,27 @@ class WC_AJAX {
$item_tax_status = 'taxable';
}
if ( '0' !== $tax_class && 'taxable' === $item_tax_status ) {
if ( '0' !== $order_item_tax_class[ $item_id ] && 'taxable' === $item_tax_status ) {
$tax_rates = WC_Tax::find_rates( array(
'country' => $country,
'state' => $state,
'postcode' => $postcode,
'city' => $city,
'tax_class' => $tax_class
'tax_class' => $order_item_tax_class[ $item_id ]
) );
$line_subtotal_taxes = WC_Tax::calc_tax( $line_subtotal, $tax_rates, false );
$line_taxes = WC_Tax::calc_tax( $line_total, $tax_rates, false );
$line_subtotal_tax = max( 0, array_sum( $line_subtotal_taxes ) );
$line_tax = max( 0, array_sum( $line_taxes ) );
$line_taxes = WC_Tax::calc_tax( $line_total[ $item_id ], $tax_rates, false );
$line_subtotal_taxes = WC_Tax::calc_tax( $line_subtotal[ $item_id ], $tax_rates, false );
$item_taxes[ $item_id ] = array(
'line_subtotal_tax' => wc_format_localized_price( $line_subtotal_tax ),
'line_tax' => wc_format_localized_price( $line_tax )
);
// Set the new line_tax
foreach ( $line_taxes as $_tax_id => $_tax_value ) {
$items['line_tax'][ $item_id ][ $_tax_id ] = $_tax_value;
}
$item_tax += $line_tax;
// Set the new line_subtotal_tax
foreach ( $line_subtotal_taxes as $_tax_id => $_tax_value ) {
$items['line_subtotal_tax'][ $item_id ][ $_tax_id ] = $_tax_value;
}
// Sum the item taxes
foreach ( array_keys( $taxes + $line_taxes ) as $key ) {
@ -1224,7 +1328,8 @@ class WC_AJAX {
}
}
// Now calculate shipping tax
// Get shipping taxes
if ( isset( $items['shipping_method_id'] ) ) {
$matched_tax_rates = array();
$tax_rates = WC_Tax::find_rates( array(
@ -1243,8 +1348,23 @@ class WC_AJAX {
}
}
$shipping_taxes = WC_Tax::calc_shipping_tax( $shipping, $matched_tax_rates );
$shipping_tax = WC_Tax::round( array_sum( $shipping_taxes ) );
$get_values = array( 'shipping_method_id', 'shipping_cost', 'shipping_taxes' );
foreach ( $get_values as $value ) {
$$value = isset( $items[ $value ] ) ? $items[ $value ] : array();
}
foreach ( $shipping_method_id as $item_id ) {
$item_id = absint( $item_id );
$shipping_cost[ $item_id ] = isset( $shipping_cost[ $item_id ] ) ? wc_format_decimal( $shipping_cost[ $item_id ] ) : 0;
$shipping_taxes = WC_Tax::calc_shipping_tax( $shipping_cost[ $item_id ], $matched_tax_rates );
// Set the new shipping_taxes
foreach ( $shipping_taxes as $_tax_id => $_tax_value ) {
$items['shipping_taxes'][ $item_id ][ $_tax_id ] = $_tax_value;
}
}
}
// Remove old tax rows
$order->remove_order_items( 'tax' );
@ -1254,21 +1374,60 @@ class WC_AJAX {
$order->add_tax( $tax_rate_id, isset( $taxes[ $tax_rate_id ] ) ? $taxes[ $tax_rate_id ] : 0, isset( $shipping_taxes[ $tax_rate_id ] ) ? $shipping_taxes[ $tax_rate_id ] : 0 );
}
ob_start();
foreach ( $order->get_taxes() as $item_id => $item ) {
include( 'admin/meta-boxes/views/html-order-tax.php' );
// Create the new order_taxes
foreach ( $order->get_taxes() as $tax_id => $tax_item ) {
$items['order_taxes'][ $tax_id ] = absint( $tax_item['rate_id'] );
}
$tax_row_html = ob_get_clean();
// Save order items
wc_save_order_items( $order_id, $items );
wp_send_json( array(
'item_tax' => $item_tax,
'item_taxes' => $item_taxes,
'shipping_tax' => $shipping_tax,
'tax_row_html' => $tax_row_html
) );
// Return HTML items
$order = new WC_Order( $order_id );
$data = get_post_meta( $order_id );
include( 'admin/meta-boxes/views/html-order-items.php' );
die();
}
/**
* Save order items via ajax
*/
public static function save_order_items() {
check_ajax_referer( 'order-item', 'security' );
if ( isset( $_POST['order_id'] ) && isset( $_POST['items'] ) ) {
$order_id = absint( $_POST['order_id'] );
// Parse the jQuery serialized items
$items = array();
parse_str( $_POST['items'], $items );
// Save order items
wc_save_order_items( $order_id, $items );
// Return HTML items
$order = new WC_Order( $order_id );
$data = get_post_meta( $order_id );
include( 'admin/meta-boxes/views/html-order-items.php' );
}
die();
}
/**
* Load order items via ajax
*/
public static function load_order_items() {
check_ajax_referer( 'order-item', 'security' );
// Return HTML items
$order_id = absint( $_POST['order_id'] );
$order = new WC_Order( $order_id );
$data = get_post_meta( $order_id );
include( 'admin/meta-boxes/views/html-order-items.php' );
die();
}
/**
@ -1624,7 +1783,113 @@ class WC_AJAX {
}
wp_send_json( $new_pos );
}
/**
* Handle a refund via the edit order screen
*/
public static function refund_line_items() {
check_ajax_referer( 'order-item', 'security' );
$order_id = absint( $_POST['order_id'] );
$refund_amount = sanitize_text_field( $_POST['refund_amount'] );
$refund_reason = sanitize_text_field( $_POST['refund_reason'] );
$line_item_qtys = json_decode( sanitize_text_field( stripslashes( $_POST['line_item_qtys'] ) ), true );
$line_item_totals = json_decode( sanitize_text_field( stripslashes( $_POST['line_item_totals'] ) ), true );
$line_item_tax_totals = json_decode( sanitize_text_field( stripslashes( $_POST['line_item_tax_totals'] ) ), true );
$api_refund = $_POST['api_refund'] === 'true' ? true : false;
$restock_refunded_items = $_POST['restock_refunded_items'] === 'true' ? true : false;
try {
// Validate that the refund can occur
$order = get_order( $order_id );
$order_items = $order->get_items();
$max_refund = $order->get_total() - $order->get_total_refunded();
if ( ! $refund_amount || $max_refund < $refund_amount ) {
throw new exception( __( 'Invalid refund amount', 'woocommerce' ) );
}
// Prepare line items which we are refunding
$line_items = array();
$item_ids = array_unique( array_merge( array_keys( $line_item_qtys, $line_item_totals ) ) );
foreach ( $item_ids as $item_id ) {
$line_items[ $item_id ] = array( 'qty' => 0, 'refund_total' => 0, 'refund_tax' => array() );
}
foreach ( $line_item_qtys as $item_id => $qty ) {
$line_items[ $item_id ]['qty'] = max( $qty, 0 );
if ( $restock_refunded_items && $qty && isset( $order_items[ $item_id ] ) ) {
$order_item = $order_items[ $item_id ];
$_product = $order->get_product_from_item( $order_item );
if ( $_product && $_product->exists() && $_product->managing_stock() ) {
$old_stock = $_product->stock;
$new_quantity = $_product->increase_stock( $qty );
$order->add_order_note( sprintf( __( 'Item #%s stock increased from %s to %s.', 'woocommerce' ), $order_item['product_id'], $old_stock, $new_quantity ) );
}
}
}
foreach ( $line_item_totals as $item_id => $total ) {
$line_items[ $item_id ]['refund_total'] = $total;
}
foreach ( $line_item_tax_totals as $item_id => $tax_totals ) {
$line_items[ $item_id ]['refund_tax'] = $tax_totals;
}
// Create the refund object
$refund = wc_create_refund( array(
'amount' => $refund_amount,
'reason' => $refund_reason,
'order_id' => $order_id,
'line_items' => $line_items
) );
if ( is_wp_error( $refund ) ) {
throw new exception( $refund->get_error_message() );
}
// Refund via API
if ( $api_refund ) {
if ( WC()->payment_gateways() ) {
$payment_gateways = WC()->payment_gateways->payment_gateways();
}
if ( isset( $payment_gateways[ $order->payment_method ] ) && $payment_gateways[ $order->payment_method ]->supports( 'refunds' ) ) {
$result = $payment_gateways[ $order->payment_method ]->process_refund( $order_id, $refund_amount );
if ( is_wp_error( $result ) ) {
throw new exception( $result->get_error_message() );
} elseif ( ! $result ) {
throw new exception( __( 'Refund failed', 'woocommerce' ) );
}
}
}
// Clear transients
wc_delete_shop_order_transients( $order_id );
wp_send_json( true );
} catch ( Exception $e ) {
wp_send_json( array( 'error' => $e->getMessage() ) );
}
}
/**
* Delete a refund
*/
public static function delete_refund() {
check_ajax_referer( 'order-item', 'security' );
$refund_id = absint( $_POST['refund_id'] );
if ( $refund_id && 'shop_order_refund' === get_post_type( $refund_id ) ) {
wp_delete_post( $refund_id );
}
die();
}
}

View File

@ -484,7 +484,7 @@ class WC_Cart {
WHERE order_item_meta.meta_key = '_qty'
AND order_item_meta2.meta_key = %s AND order_item_meta2.meta_value = %d
AND posts.post_type = 'shop_order'
AND posts.post_type IN ( '" . implode( ',', wc_get_order_types() ) . "' )
AND posts.post_status = 'wc-pending'
AND posts.ID != %d
", $key, $value, $order_id ) );
@ -1103,6 +1103,10 @@ class WC_Cart {
$base_price = $_product->get_price();
$line_price = $_product->get_price() * $values['quantity'];
// Tax data
$taxes = array();
$discounted_taxes = array();
/**
* No tax to calculate
*/
@ -1211,6 +1215,9 @@ class WC_Cart {
$this->cart_contents[ $cart_item_key ]['line_tax'] = $line_tax;
$this->cart_contents[ $cart_item_key ]['line_subtotal'] = $line_subtotal;
$this->cart_contents[ $cart_item_key ]['line_subtotal_tax'] = $line_subtotal_tax;
// Store rates ID and costs - Since 2.2
$this->cart_contents[ $cart_item_key ]['line_tax_data'] = array( 'total' => $discounted_taxes, 'subtotal' => $taxes );
}
// Only calculate the grand total + shipping if on the cart/checkout
@ -1882,6 +1889,7 @@ class WC_Cart {
$new_fee->tax_class = $tax_class;
$new_fee->taxable = $taxable ? true : false;
$new_fee->tax = 0;
$new_fee->tax_data = array();
$this->fees[] = $new_fee;
}
@ -1917,6 +1925,9 @@ class WC_Cart {
// Set the tax total for this fee
$this->fees[ $fee_key ]->tax = array_sum( $fee_taxes );
// Set tax data - Since 2.2
$this->fees[ $fee_key ]->tax_data = $fee_taxes;
// Tax rows - merge the totals we just got
foreach ( array_keys( $this->taxes + $fee_taxes ) as $key ) {
$this->taxes[ $key ] = ( isset( $fee_taxes[ $key ] ) ? $fee_taxes[ $key ] : 0 ) + ( isset( $this->taxes[ $key ] ) ? $this->taxes[ $key ] : 0 );

View File

@ -178,7 +178,7 @@ class WC_Checkout {
$order_id = absint( WC()->session->order_awaiting_payment );
// Resume the unpaid order if its pending
if ( $order_id > 0 && ( $order = new WC_Order( $order_id ) ) && $order->has_status( array( 'pending', 'failed' ) ) ) {
if ( $order_id > 0 && ( $order = get_order( $order_id ) ) && $order->has_status( array( 'pending', 'failed' ) ) ) {
$order_data['order_id'] = $order_id;
$order = wc_update_order( $order_data );
@ -213,7 +213,8 @@ class WC_Checkout {
'subtotal' => $values['line_subtotal'],
'subtotal_tax' => $values['line_subtotal_tax'],
'total' => $values['line_total'],
'tax' => $values['line_tax']
'tax' => $values['line_tax'],
'tax_data' => $values['line_tax_data'] // Since 2.2
)
)
);

View File

@ -49,7 +49,7 @@ class WC_Comments {
public static function exclude_order_comments( $clauses ) {
global $wpdb, $typenow;
if ( is_admin() && $typenow == 'shop_order' && current_user_can( 'manage_woocommerce' ) )
if ( is_admin() && in_array( $typenow, wc_get_order_types() ) && current_user_can( 'manage_woocommerce' ) )
return $clauses; // Don't hide when viewing orders in admin
if ( ! $clauses['join'] )
@ -61,7 +61,7 @@ class WC_Comments {
if ( $clauses['where'] )
$clauses['where'] .= ' AND ';
$clauses['where'] .= " $wpdb->posts.post_type NOT IN ('shop_order') ";
$clauses['where'] .= " $wpdb->posts.post_type NOT IN ('" . implode( ',', wc_get_order_types() ) . "') ";
return $clauses;
}
@ -93,7 +93,7 @@ class WC_Comments {
if ( $where )
$where .= ' AND ';
$where .= " $wpdb->posts.post_type NOT IN ('shop_order') ";
$where .= " $wpdb->posts.post_type NOT IN ('" . implode( ',', wc_get_order_types() ) . "') ";
return $where;
}

View File

@ -30,27 +30,25 @@ class WC_Order_Factory {
$the_order = get_post( $the_order );
}
if ( ! $the_order )
if ( ! $the_order || ! is_object( $the_order ) ) {
return false;
if ( is_object ( $the_order ) ) {
$order_id = absint( $the_order->ID );
$post_type = $the_order->post_type;
}
if ( 'shop_order' == $post_type ) {
$classname = 'WC_Order';
$order_type = 'simple';
$order_id = absint( $the_order->ID );
$post_type = $the_order->post_type;
if ( $order_type = wc_get_order_type( $post_type ) ) {
$classname = $order_type['class_name'];
} else {
$classname = false;
$order_type = false;
}
// Filter classname so that the class can be overridden if extended.
$classname = apply_filters( 'woocommerce_order_class', $classname, $order_type, $post_type, $order_id );
$classname = apply_filters( 'woocommerce_order_class', $classname, $post_type, $order_id );
if ( ! class_exists( $classname ) )
if ( ! class_exists( $classname ) ) {
$classname = 'WC_Order';
}
return new $classname( $the_order, $args );
}

View File

@ -0,0 +1,92 @@
<?php
/**
* Order refund
*
* @class WC_Order_Refund
* @version 2.2.0
* @package WooCommerce/Classes
* @category Class
* @author WooThemes
*/
class WC_Order_Refund extends WC_Abstract_Order {
/**
* Initialize the order refund.
*
* @param int|WC_Order_Refund $refund
*/
public function __construct( $refund ) {
$this->order_type = 'refund';
if ( is_numeric( $refund ) ) {
$this->id = absint( $refund );
$this->post = get_post( $refund );
$this->get_refund( $this->id );
} elseif ( $refund instanceof WC_Order_Refund ) {
$this->id = absint( $refund->id );
$this->post = $refund->post;
$this->get_refund( $this->id );
} elseif ( $refund instanceof WC_Order_Refund || isset( $refund->ID ) ) {
$this->id = absint( $refund->ID );
$this->post = $refund;
$this->get_refund( $this->id );
}
}
/**
* Gets an refund from the database
*
* @since 2.2
* @param int $id
* @return bool
*/
public function get_refund( $id = 0 ) {
if ( ! $id ) {
return false;
}
if ( $result = get_post( $id ) ) {
$this->populate( $result );
return true;
}
return false;
}
/**
* Populates an refund from the loaded post data
*
* @since 2.2
* @param mixed $result
* @return void
*/
public function populate( $result ) {
// Standard post data
$this->id = $result->ID;
$this->date = $result->post_date;
$this->modified_date = $result->post_modified;
$this->reason = $result->post_excerpt;
}
/**
* Get refunded amount
*
* @since 2.2
* @return int|float
*/
public function get_refund_amount() {
return apply_filters( 'woocommerce_refund_amount', (double) $this->refund_amount, $this );
}
/**
* Get refunded amount
*
* @since 2.2
* @return int|float
*/
public function get_refund_reason() {
return apply_filters( 'woocommerce_refund_reason', $this->reason, $this );
}
}

View File

@ -1,18 +1,150 @@
<?php
/**
* Order
*
* @class WC_Order
* @version 2.1.0
* @version 2.2.0
* @package WooCommerce/Classes
* @category Class
* @author WooThemes
*/
class WC_Order extends WC_Abstract_Order {
/**
* Initialize the order refund.
*
* @param int|WC_Order $order
*/
public function __construct( $order ) {
$this->order_type = 'simple';
parent::__construct( $order );
}
/**
* Get order refunds
*
* @since 2.2
* @return array
*/
public function get_refunds() {
if ( empty( $this->refunds ) && ! is_array( $this->refunds ) ) {
$refunds = array();
$refund_items = get_posts(
array(
'post_type' => 'shop_order_refund',
'post_parent' => $this->id,
'posts_per_page' => -1,
'post_status' => 'any',
'fields' => 'ids'
)
);
foreach ( $refund_items as $refund_id ) {
$refunds[] = new WC_Order_Refund( $refund_id );
}
$this->refunds = $refunds;
}
return $this->refunds;
}
/**
* Get amount already refunded
*
* @since 2.2
* @return int|float
*/
public function get_total_refunded() {
global $wpdb;
$total = $wpdb->get_var( $wpdb->prepare( "
SELECT SUM( postmeta.meta_value )
FROM $wpdb->postmeta AS postmeta
INNER JOIN $wpdb->posts AS posts ON ( posts.post_type = 'shop_order_refund' AND posts.post_parent = %d )
WHERE postmeta.meta_key = '_refund_amount'
AND postmeta.post_id = posts.ID
", $this->id ) );
return $total;
}
/**
* Get the refunded amount for a line item
*
* @param int $item_id ID of the item we're checking
* @param string $item_type type of the item we're checking, if not a line_item
* @return float|int
*/
public function get_qty_refunded_for_item( $item_id, $item_type = 'line_item' ) {
$qty = 0;
foreach ( $this->get_refunds() as $refund ) {
foreach ( $refund->get_items( $item_type ) as $refunded_item ) {
if ( isset( $refunded_item['refunded_item_id'] ) && $refunded_item['refunded_item_id'] == $item_id ) {
$qty += $refunded_item['qty'];
}
}
}
return $qty;
}
/**
* Get the refunded amount for a line item
*
* @param int $item_id ID of the item we're checking
* @param string $item_type type of the item we're checking, if not a line_item
* @return float|int
*/
public function get_total_refunded_for_item( $item_id, $item_type = 'line_item' ) {
$total = 0;
foreach ( $this->get_refunds() as $refund ) {
foreach ( $refund->get_items( $item_type ) as $refunded_item ) {
if ( isset( $refunded_item['refunded_item_id'] ) && $refunded_item['refunded_item_id'] == $item_id ) {
switch ( $item_type ) {
case 'shipping' :
$total += $refunded_item['cost'];
break;
default :
$total += $refunded_item['line_total'];
break;
}
}
}
}
return $total * -1;
}
/**
* Get the refunded amount for a line item
*
* @param int $item_id ID of the item we're checking
* @param int $tax_id ID of the tax we're checking
* @param string $item_type type of the item we're checking, if not a line_item
* @return float|int
*/
public function get_tax_refunded_for_item( $item_id, $tax_id, $item_type = 'line_item' ) {
$total = 0;
foreach ( $this->get_refunds() as $refund ) {
foreach ( $refund->get_items( $item_type ) as $refunded_item ) {
if ( isset( $refunded_item['refunded_item_id'] ) && $refunded_item['refunded_item_id'] == $item_id ) {
switch ( $item_type ) {
case 'shipping' :
$tax_data = maybe_unserialize( $refunded_item['taxes'] );
if ( isset( $tax_data[ $tax_id ] ) ) {
$total += $tax_data[ $tax_id ];
}
break;
default :
$tax_data = maybe_unserialize( $refunded_item['line_tax_data'] );
if ( isset( $tax_data['total'][ $tax_id ] ) ) {
$total += $tax_data['total'][ $tax_id ];
}
break;
}
}
}
}
return $total * -1;
}
}

View File

@ -146,7 +146,7 @@ class WC_Post_Data {
* @return null|bool
*/
public static function update_post_metadata( $check, $object_id, $meta_key, $meta_value, $prev_value ) {
if ( ! empty( $meta_value ) && is_float( $meta_value ) && in_array( get_post_type( $object_id ), array( 'shop_order', 'shop_coupon', 'product', 'product_variation' ) ) ) {
if ( ! empty( $meta_value ) && is_float( $meta_value ) && in_array( get_post_type( $object_id ), array_merge( wc_get_order_types(), array( 'shop_coupon', 'product', 'product_variation' ) ) ) ) {
// Convert float to string
$meta_value = wc_float_to_string( $meta_value );

View File

@ -30,8 +30,9 @@ class WC_Post_types {
* Register WooCommerce taxonomies.
*/
public static function register_taxonomies() {
if ( taxonomy_exists( 'product_type' ) )
if ( taxonomy_exists( 'product_type' ) ) {
return;
}
do_action( 'woocommerce_register_taxonomy' );
@ -206,15 +207,16 @@ class WC_Post_types {
* Register core post types
*/
public static function register_post_types() {
if ( post_type_exists('product') )
if ( post_type_exists('product') ) {
return;
}
do_action( 'woocommerce_register_post_type' );
$permalinks = get_option( 'woocommerce_permalinks' );
$product_permalink = empty( $permalinks['product_base'] ) ? _x( 'product', 'slug', 'woocommerce' ) : $permalinks['product_base'];
register_post_type( "product",
register_post_type( 'product',
apply_filters( 'woocommerce_register_post_type_product',
array(
'labels' => array(
@ -254,7 +256,7 @@ class WC_Post_types {
add_rewrite_rule( '^' . $matches[1] . '/.+?/[^/]+/([^/]+)/?$', 'index.php?attachment=$matches[1]', 'top' );
}
register_post_type( "product_variation",
register_post_type( 'product_variation',
apply_filters( 'woocommerce_register_post_type_product_variation',
array(
'label' => __( 'Variations', 'woocommerce' ),
@ -265,13 +267,14 @@ class WC_Post_types {
)
);
$menu_name = _x('Orders', 'Admin menu name', 'woocommerce' );
$menu_name = _x( 'Orders', 'Admin menu name', 'woocommerce' );
if ( $order_count = wc_processing_order_count() ) {
$menu_name .= " <span class='awaiting-mod update-plugins count-$order_count'><span class='processing-count'>" . number_format_i18n( $order_count ) . "</span></span>" ;
$menu_name .= ' <span class="awaiting-mod update-plugins count-' . $order_count . '"><span class="processing-count">' . number_format_i18n( $order_count ) . '</span></span>';
}
register_post_type( "shop_order",
wc_register_order_type(
'shop_order',
apply_filters( 'woocommerce_register_post_type_shop_order',
array(
'labels' => array(
@ -308,8 +311,26 @@ class WC_Post_types {
)
);
if ( get_option( 'woocommerce_enable_coupons' ) == 'yes' ) {
register_post_type( "shop_coupon",
wc_register_order_type(
'shop_order_refund',
apply_filters( 'woocommerce_register_post_type_shop_order_refund',
array(
'label' => __( 'Refunds', 'woocommerce' ),
'capability_type' => 'shop_order',
'public' => false,
'hierarchical' => false,
'supports' => false,
'exclude_from_orders_screen' => false,
'add_order_meta_boxes' => false,
'exclude_from_order_count' => true,
'exclude_from_order_views' => false,
'class_name' => 'WC_Order_Refund'
)
)
);
if ( 'yes' == get_option( 'woocommerce_enable_coupons' ) ) {
register_post_type( 'shop_coupon',
apply_filters( 'woocommerce_register_post_type_shop_coupon',
array(
'labels' => array(

View File

@ -517,38 +517,70 @@ class WC_Tax {
/**
* Return a given rates label.
*
* @param int key
* @param mixed $key_or_rate Tax rate ID, or the db row itself in object format
* @return string
*/
public static function get_rate_label( $key ) {
public static function get_rate_label( $key_or_rate ) {
global $wpdb;
if ( is_object( $key_or_rate ) ) {
$key = $key_or_rate->tax_rate_id;
$rate_name = $key_or_rate->tax_rate_name;
} else {
$key = $key_or_rate;
$rate_name = $wpdb->get_var( $wpdb->prepare( "SELECT tax_rate_name FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %s", $key ) );
}
if ( ! $rate_name )
if ( ! $rate_name ) {
$rate_name = WC()->countries->tax_or_vat();
}
return apply_filters( 'woocommerce_rate_label', $rate_name, $key );
}
/**
* Return a given rates percent.
*
* @param mixed $key_or_rate Tax rate ID, or the db row itself in object format
* @return string
*/
public static function get_rate_percent( $key_or_rate ) {
global $wpdb;
if ( is_object( $key_or_rate ) ) {
$key = $key_or_rate->tax_rate_id;
$tax_rate = $key_or_rate->tax_rate;
} else {
$key = $key_or_rate;
$tax_rate = $wpdb->get_var( $wpdb->prepare( "SELECT tax_rate FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %s", $key ) );
}
return apply_filters( 'woocommerce_rate_percent', floatval( $tax_rate ) . '%', $key );
}
/**
* Get a rates code. Code is made up of COUNTRY-STATE-NAME-Priority. E.g GB-VAT-1, US-AL-TAX-1
*
* @access public
* @param mixed $key
* @param mixed $key_or_rate Tax rate ID, or the db row itself in object format
* @return string
*/
public static function get_rate_code( $key ) {
public static function get_rate_code( $key_or_rate ) {
global $wpdb;
if ( is_object( $key_or_rate ) ) {
$key = $key_or_rate->tax_rate_id;
$rate = $key_or_rate;
} else {
$key = $key_or_rate;
$rate = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %s", $key ) );
}
if ( ! $rate ) {
return '';
}
$code = array();
$code[] = $rate->tax_rate_country;
$code[] = $rate->tax_rate_state;
$code[] = $rate->tax_rate_name ? $rate->tax_rate_name : 'TAX';

View File

@ -33,6 +33,10 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway {
$this->method_title = __( 'PayPal', 'woocommerce' );
$this->view_transaction_url = 'https://www.paypal.com/cgi-bin/webscr?cmd=_view-a-trans&id=%s';
$this->notify_url = WC()->api_request_url( 'WC_Gateway_Paypal' );
$this->supports = array(
'products',
'refunds'
);
// Load the settings.
$this->init_form_fields();
@ -47,11 +51,13 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway {
$this->send_shipping = $this->get_option( 'send_shipping' );
$this->address_override = $this->get_option( 'address_override' );
$this->debug = $this->get_option( 'debug' );
$this->form_submission_method = $this->get_option( 'form_submission_method' ) == 'yes' ? true : false;
$this->page_style = $this->get_option( 'page_style' );
$this->invoice_prefix = $this->get_option( 'invoice_prefix', 'WC-' );
$this->paymentaction = $this->get_option( 'paymentaction', 'sale' );
$this->identity_token = $this->get_option( 'identity_token', '' );
$this->api_username = $this->get_option( 'api_username' );
$this->api_password = $this->get_option( 'api_password' );
$this->api_signature = $this->get_option( 'api_signature' );
// Logs
if ( 'yes' == $this->debug ) {
@ -119,8 +125,7 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway {
* @access public
* @return void
*/
function init_form_fields() {
public function init_form_fields() {
$this->form_fields = array(
'enabled' => array(
'title' => __( 'Enable/Disable', 'woocommerce' ),
@ -137,7 +142,8 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway {
),
'description' => array(
'title' => __( 'Description', 'woocommerce' ),
'type' => 'textarea',
'type' => 'text',
'desc_tip' => true,
'description' => __( 'This controls the description which the user sees during checkout.', 'woocommerce' ),
'default' => __( 'Pay via PayPal; you can pay with your credit card if you don\'t have a PayPal account', 'woocommerce' )
),
@ -149,54 +155,19 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway {
'desc_tip' => true,
'placeholder' => 'you@youremail.com'
),
'receiver_email' => array(
'title' => __( 'Receiver Email', 'woocommerce' ),
'type' => 'email',
'description' => __( 'If this differs from the email entered above, input your main receiver email for your PayPal account. This is used to validate IPN requests.', 'woocommerce' ),
'default' => '',
'desc_tip' => true,
'placeholder' => 'you@youremail.com'
),
'identity_token' => array(
'title' => __( 'PayPal Identity Token', 'woocommerce' ),
'type' => 'text',
'description' => __( 'Optionally enable "Payment Data Transfer" (Profile > Website Payment Preferences) and then copy your identity token here. This will allow payments to be verified without the need for PayPal IPN.', 'woocommerce' ),
'default' => '',
'desc_tip' => true,
'placeholder' => __( 'Optional', 'woocommerce' )
),
'invoice_prefix' => array(
'title' => __( 'Invoice Prefix', 'woocommerce' ),
'type' => 'text',
'description' => __( 'Please enter a prefix for your invoice numbers. If you use your PayPal account for multiple stores ensure this prefix is unique as PayPal will not allow orders with the same invoice number.', 'woocommerce' ),
'default' => 'WC-',
'desc_tip' => true,
),
'paymentaction' => array(
'title' => __( 'Payment Action', 'woocommerce' ),
'type' => 'select',
'description' => __( 'Choose whether you wish to capture funds immediately or authorize payment only.', 'woocommerce' ),
'default' => 'sale',
'desc_tip' => true,
'options' => array(
'sale' => __( 'Capture', 'woocommerce' ),
'authorization' => __( 'Authorize', 'woocommerce' )
)
),
'form_submission_method' => array(
'title' => __( 'Submission method', 'woocommerce' ),
'testmode' => array(
'title' => __( 'PayPal sandbox', 'woocommerce' ),
'type' => 'checkbox',
'label' => __( 'Use form submission method.', 'woocommerce' ),
'description' => __( 'Enable this to post order data to PayPal via a form instead of using a redirect/querystring.', 'woocommerce' ),
'default' => 'no'
'label' => __( 'Enable PayPal sandbox', 'woocommerce' ),
'default' => 'no',
'description' => sprintf( __( 'PayPal sandbox can be used to test payments. Sign up for a developer account <a href="%s">here</a>.', 'woocommerce' ), 'https://developer.paypal.com/' ),
),
'page_style' => array(
'title' => __( 'Page Style', 'woocommerce' ),
'type' => 'text',
'description' => __( 'Optionally enter the name of the page style you wish to use. These are defined within your PayPal account.', 'woocommerce' ),
'default' => '',
'desc_tip' => true,
'placeholder' => __( 'Optional', 'woocommerce' )
'debug' => array(
'title' => __( 'Debug Log', 'woocommerce' ),
'type' => 'checkbox',
'label' => __( 'Enable logging', 'woocommerce' ),
'default' => 'no',
'description' => sprintf( __( 'Log PayPal events, such as IPN requests, inside <code>%s</code>', 'woocommerce' ), wc_get_log_file_path( 'paypal' ) )
),
'shipping' => array(
'title' => __( 'Shipping options', 'woocommerce' ),
@ -217,25 +188,82 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway {
'description' => __( 'PayPal verifies addresses therefore this setting can cause errors (we recommend keeping it disabled).', 'woocommerce' ),
'default' => 'no'
),
'testing' => array(
'title' => __( 'Gateway Testing', 'woocommerce' ),
'advanced' => array(
'title' => __( 'Advanced options', 'woocommerce' ),
'type' => 'title',
'description' => '',
),
'testmode' => array(
'title' => __( 'PayPal sandbox', 'woocommerce' ),
'type' => 'checkbox',
'label' => __( 'Enable PayPal sandbox', 'woocommerce' ),
'default' => 'no',
'description' => sprintf( __( 'PayPal sandbox can be used to test payments. Sign up for a developer account <a href="%s">here</a>.', 'woocommerce' ), 'https://developer.paypal.com/' ),
'receiver_email' => array(
'title' => __( 'Receiver Email', 'woocommerce' ),
'type' => 'email',
'description' => __( 'If your main PayPal email differs from the PayPal email entered above, input your main receiver email for your PayPal account here. This is used to validate IPN requests.', 'woocommerce' ),
'default' => '',
'desc_tip' => true,
'placeholder' => 'you@youremail.com'
),
'debug' => array(
'title' => __( 'Debug Log', 'woocommerce' ),
'type' => 'checkbox',
'label' => __( 'Enable logging', 'woocommerce' ),
'default' => 'no',
'description' => sprintf( __( 'Log PayPal events, such as IPN requests, inside <code>%s</code>', 'woocommerce' ), wc_get_log_file_path( 'paypal' ) )
'invoice_prefix' => array(
'title' => __( 'Invoice Prefix', 'woocommerce' ),
'type' => 'text',
'description' => __( 'Please enter a prefix for your invoice numbers. If you use your PayPal account for multiple stores ensure this prefix is unique as PayPal will not allow orders with the same invoice number.', 'woocommerce' ),
'default' => 'WC-',
'desc_tip' => true,
),
'paymentaction' => array(
'title' => __( 'Payment Action', 'woocommerce' ),
'type' => 'select',
'description' => __( 'Choose whether you wish to capture funds immediately or authorize payment only.', 'woocommerce' ),
'default' => 'sale',
'desc_tip' => true,
'options' => array(
'sale' => __( 'Capture', 'woocommerce' ),
'authorization' => __( 'Authorize', 'woocommerce' )
)
),
'page_style' => array(
'title' => __( 'Page Style', 'woocommerce' ),
'type' => 'text',
'description' => __( 'Optionally enter the name of the page style you wish to use. These are defined within your PayPal account.', 'woocommerce' ),
'default' => '',
'desc_tip' => true,
'placeholder' => __( 'Optional', 'woocommerce' )
),
'identity_token' => array(
'title' => __( 'PayPal Identity Token', 'woocommerce' ),
'type' => 'text',
'description' => __( 'Optionally enable "Payment Data Transfer" (Profile > Website Payment Preferences) and then copy your identity token here. This will allow payments to be verified without the need for PayPal IPN.', 'woocommerce' ),
'default' => '',
'desc_tip' => true,
'placeholder' => __( 'Optional', 'woocommerce' )
),
'api_details' => array(
'title' => __( 'API options (for refund support)', 'woocommerce' ),
'type' => 'title',
'description' => '',
),
'api_username' => array(
'title' => __( 'API Username', 'woocommerce' ),
'type' => 'text',
'description' => __( 'Get your API credentials from PayPal.', 'woocommerce' ),
'default' => '',
'desc_tip' => true,
'placeholder' => __( 'Optional', 'woocommerce' )
),
'api_password' => array(
'title' => __( 'API Password', 'woocommerce' ),
'type' => 'text',
'description' => __( 'Get your API credentials from PayPal.', 'woocommerce' ),
'default' => '',
'desc_tip' => true,
'placeholder' => __( 'Optional', 'woocommerce' )
),
'api_signature' => array(
'title' => __( 'API Signature', 'woocommerce' ),
'type' => 'text',
'description' => __( 'Get your API credentials from PayPal.', 'woocommerce' ),
'default' => '',
'desc_tip' => true,
'placeholder' => __( 'Optional', 'woocommerce' )
),
);
}
@ -504,14 +532,9 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway {
* @param int $order_id
* @return array
*/
function process_payment( $order_id ) {
public function process_payment( $order_id ) {
$order = get_order( $order_id );
if ( ! $this->form_submission_method ) {
$paypal_args = $this->get_paypal_args( $order );
$paypal_args = http_build_query( $paypal_args, '', '&' );
if ( 'yes' == $this->testmode ) {
@ -524,16 +547,65 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway {
'result' => 'success',
'redirect' => $paypal_adr . $paypal_args
);
} else {
return array(
'result' => 'success',
'redirect' => $order->get_checkout_payment_url( true )
);
}
/**
* Process a refund if supported
* @param int $order_id
* @param float $amount
* @return bool|wp_error True or false based on success, or a WP_Error object
*/
public function process_refund( $order_id, $amount = null ) {
$order = get_order( $order_id );
if ( ! $order || ! $order->get_transaction_id() || ! $this->api_username || ! $this->api_password || ! $this->api_password ) {
return false;
}
$post_data = array(
'VERSION' => '84.0',
'SIGNATURE' => $this->api_signature,
'USER' => $this->api_username,
'PWD' => $this->api_password,
'METHOD' => 'RefundTransaction',
'TRANSACTIONID' => $order->get_transaction_id(),
'REFUNDTYPE' => is_null( $amount ) ? 'Full' : 'Partial'
);
if ( ! is_null( $amount ) ) {
$post_data['AMT'] = number_format( $amount, 2, '.', '' );
$post_data['CURRENCYCODE'] = $order->get_order_currency();
}
$response = wp_remote_post( 'yes' === $this->testmode ? 'https://api-3t.sandbox.paypal.com/nvp' : 'https://api-3t.paypal.com/nvp', array(
'method' => 'POST',
'body' => $post_data,
'timeout' => 70,
'sslverify' => false,
'user-agent' => 'WooCommerce',
'httpversion' => '1.1'
)
);
if ( is_wp_error( $response ) ) {
return $response;
}
if ( empty( $response['body'] ) ) {
return new WP_Error( 'paypal-error', __( 'Empty Paypal response.', 'woocommerce' ) );
}
parse_str( $response['body'], $parsed_response );
switch ( strtolower( $parsed_response['ACK'] ) ) {
case 'success':
case 'successwithwarning':
$order->add_order_note( sprintf( __( 'Refunded %s - Refund ID: %s', 'woocommerce' ), $parsed_response['GROSSREFUNDAMT'], $parsed_response['REFUNDTRANSACTIONID'] ) );
return true;
break;
}
return false;
}
/**

View File

@ -166,6 +166,14 @@ function wc_round_tax_total( $tax ) {
return $tax;
}
/**
* Make a refund total negative
* @return float
*/
function wc_format_refund_total( $amount ) {
return $amount * -1;
}
/**
* Format decimal numbers ready for DB storage
*
@ -321,6 +329,13 @@ function wc_price( $price, $args = array() ) {
$decimal_sep = wp_specialchars_decode( stripslashes( get_option( 'woocommerce_price_decimal_sep' ) ), ENT_QUOTES );
$thousands_sep = wp_specialchars_decode( stripslashes( get_option( 'woocommerce_price_thousand_sep' ) ), ENT_QUOTES );
if ( $price < 0 ) {
$price = $price * -1;
$negative = true;
} else {
$negative = false;
}
$price = apply_filters( 'raw_woocommerce_price', floatval( $price ) );
$price = apply_filters( 'formatted_woocommerce_price', number_format( $price, $num_decimals, $decimal_sep, $thousands_sep ), $price, $num_decimals, $decimal_sep, $thousands_sep );
@ -328,7 +343,7 @@ function wc_price( $price, $args = array() ) {
$price = wc_trim_zeros( $price );
}
$formatted_price = sprintf( get_woocommerce_price_format(), $currency_symbol, $price );
$formatted_price = ( $negative ? '-' : '' ) . sprintf( get_woocommerce_price_format(), $currency_symbol, $price );
$return = '<span class="amount">' . $formatted_price . '</span>';
if ( $ex_tax_label && get_option( 'woocommerce_calc_taxes' ) == 'yes' ) {

View File

@ -68,6 +68,132 @@ function wc_get_order_id_by_order_key( $order_key ) {
return $order_id;
}
/**
* Get all registered order types
*
* $for optionally define what you are getting order types for so only relevent types are returned.
*
* e.g. for 'order-meta-boxes', 'order-count'
*
* @since 2.2
* @param string $for
* @return array
*/
function wc_get_order_types( $for = '' ) {
global $wc_order_types;
if ( ! is_array( $wc_order_types ) ) {
$wc_order_types = array();
}
$order_types = array();
switch ( $for ) {
case 'order-count' :
foreach ( $wc_order_types as $type => $args ) {
if ( ! $args['exclude_from_order_count'] ) {
$order_types[] = $type;
}
}
break;
case 'order-meta-boxes' :
foreach ( $wc_order_types as $type => $args ) {
if ( $args['add_order_meta_boxes'] ) {
$order_types[] = $type;
}
}
break;
case 'view-orders' :
foreach ( $wc_order_types as $type => $args ) {
if ( ! $args['exclude_from_order_views'] ) {
$order_types[] = $type;
}
}
break;
case 'reports' :
foreach ( $wc_order_types as $type => $args ) {
if ( ! $args['exclude_from_order_reports'] ) {
$order_types[] = $type;
}
}
break;
default :
$order_types = array_keys( $wc_order_types );
break;
}
return apply_filters( 'wc_order_types', $order_types, $for );
}
/**
* Get an order type by post type name
* @param string post type name
* @return bool|array of datails about the order type
*/
function wc_get_order_type( $type ) {
global $wc_order_types;
if ( isset( $wc_order_types[ $type ] ) ) {
return $wc_order_types[ $type ];
} else {
return false;
}
}
/**
* Register order type. Do not use before init.
*
* Wrapper for register post type, as well as a method of telling WC which
* post types are types of orders, and having them treated as such.
*
* $args are passed to register_post_type, but there are a few specific to this function:
* - exclude_from_orders_screen (bool) Whether or not this order type also get shown in the main
* orders screen.
* - add_order_meta_boxes (bool) Whether or not the order type gets shop_order meta boxes.
* - exclude_from_order_count (bool) Whether or not this order type is excluded from counts.
* - exclude_from_order_views (bool) Whether or not this order type is visible by customers when
* viewing orders e.g. on the my account page.
* - exclude_from_order_reports (bool) Whether or not to exclude this type from core reports.
*
* @since 2.2
* @see register_post_type for $args used in that function
* @param string $type Post type. (max. 20 characters, can not contain capital letters or spaces)
* @param array $args An array of arguments.
* @return bool Success or failure
*/
function wc_register_order_type( $type, $args = array() ) {
if ( post_type_exists( $type ) ) {
return false;
}
global $wc_order_types;
if ( ! is_array( $wc_order_types ) ) {
$wc_order_types = array();
}
// Register as a post type
if ( is_wp_error( register_post_type( $type, $args ) ) ) {
return false;
}
// Register for WC usage
$order_type_args = array(
'exclude_from_orders_screen' => false,
'add_order_meta_boxes' => true,
'exclude_from_order_count' => false,
'exclude_from_order_views' => false,
'exclude_from_order_reports' => false,
'class_name' => 'WC_Order'
);
$args = array_intersect_key( $args, $order_type_args );
$args = wp_parse_args( $args, $order_type_args );
$wc_order_types[ $type ] = $args;
return true;
}
/**
* Grant downloadable product access to the file identified by $download_id
*
@ -338,7 +464,7 @@ function wc_cancel_unpaid_orders() {
$unpaid_orders = $wpdb->get_col( $wpdb->prepare( "
SELECT posts.ID
FROM {$wpdb->posts} AS posts
WHERE posts.post_type = 'shop_order'
WHERE posts.post_type IN ('" . implode( ',', wc_get_order_types() ) . "')
AND posts.post_status = 'wc-pending'
AND posts.post_modified < %s
", $date ) );
@ -365,8 +491,14 @@ add_action( 'woocommerce_cancel_unpaid_orders', 'wc_cancel_unpaid_orders' );
* @return int
*/
function wc_processing_order_count() {
$count = wp_count_posts( 'shop_order', 'readable' );
return isset( $count->processing ) ? $count->processing : 0;
$count = 0;
foreach ( wc_get_order_types( 'order-count' ) as $type ) {
$this_count = wp_count_posts( $type, 'readable' );
$count += isset( $count->processing ) ? $count->processing : 0;
}
return $count;
}
/**
@ -404,3 +536,160 @@ function wc_delete_shop_order_transients( $post_id = 0 ) {
function wc_ship_to_billing_address_only() {
return 'billing_only' === get_option( 'woocommerce_ship_to_destination' );
}
/**
* Create a new order refund programmatically
*
* Returns a new refund object on success which can then be used to add additonal data.
*
* @since 2.2
* @param array $args
* @return WC_Order_Refund on success, WP_Error on failure
*/
function wc_create_refund( $args = array() ) {
$default_args = array(
'amount' => '',
'reason' => null,
'order_id' => 0,
'refund_id' => 0,
'line_items' => array()
);
$args = wp_parse_args( $args, $default_args );
$refund_data = array();
if ( $args['refund_id'] > 0 ) {
$updating = true;
$refund_data['ID'] = $args['refund_id'];
} else {
$updating = false;
$refund_data['post_type'] = 'shop_order_refund';
$refund_data['post_status'] = 'wc-completed';
$refund_data['ping_status'] = 'closed';
$refund_data['post_author'] = 1;
$refund_data['post_password'] = uniqid( 'refund_' );
$refund_data['post_parent'] = absint( $args['order_id'] );
$refund_data['post_title'] = sprintf( __( 'Refund &ndash; %s', 'woocommerce' ), strftime( _x( '%b %d, %Y @ %I:%M %p', 'Order date parsed by strftime', 'woocommerce' ) ) );
}
if ( ! is_null( $args['reason'] ) ) {
$refund_data['post_excerpt'] = $args['reason'];
}
if ( $updating ) {
$refund_id = wp_update_post( $refund_data );
} else {
$refund_id = wp_insert_post( apply_filters( 'woocommerce_new_refund_data', $refund_data ), true );
}
if ( is_wp_error( $refund_id ) ) {
return $refund_id;
}
if ( ! $updating ) {
// Default refund meta data
update_post_meta( $refund_id, '_refund_amount', wc_format_decimal( $args['amount'] ) );
// Negative line items
if ( sizeof( $args['line_items'] ) > 0 ) {
$order = get_order( $args['order_id'] );
$order_items = $order->get_items( array( 'line_item', 'fee', 'shipping' ) );
$refund = get_order( $refund_id );
foreach ( $args['line_items'] as $refund_item_id => $refund_item ) {
if ( isset( $order_items[ $refund_item_id ] ) ) {
if ( empty( $refund_item['qty'] ) && empty( $refund_item['refund_total'] ) && empty( $refund_item['refund_tax'] ) ) {
continue;
}
// Prevents errors when the order has no taxes
if ( ! isset( $refund_item['refund_tax'] ) ) {
$refund_item['refund_tax'] = array();
}
switch ( $order_items[ $refund_item_id ]['type'] ) {
case 'line_item' :
$args = array(
'totals' => array(
'subtotal' => wc_format_refund_total( $refund_item['refund_total'] ),
'total' => wc_format_refund_total( $refund_item['refund_total'] ),
'subtotal_tax' => wc_format_refund_total( array_sum( $refund_item['refund_tax'] ) ),
'tax' => wc_format_refund_total( array_sum( $refund_item['refund_tax'] ) ),
'tax_data' => array( 'total' => array_map( 'wc_format_refund_total', $refund_item['refund_tax'] ), 'subtotal' => array_map( 'wc_format_refund_total', $refund_item['refund_tax'] ) )
)
);
$new_item_id = $refund->add_product( $order->get_product_from_item( $order_items[ $refund_item_id ] ), isset( $refund_item['qty'] ) ? $refund_item['qty'] : 0, $args );
wc_add_order_item_meta( $new_item_id, '_refunded_item_id', $refund_item_id );
break;
case 'shipping' :
$shipping = new stdClass();
$shipping->label = $order_items[ $refund_item_id ]['name'];
$shipping->id = $order_items[ $refund_item_id ]['method_id'];
$shipping->cost = wc_format_refund_total( $refund_item['refund_total'] );
$shipping->taxes = array_map( 'wc_format_refund_total', $refund_item['refund_tax'] );
$new_item_id = $refund->add_shipping( $shipping );
wc_add_order_item_meta( $new_item_id, '_refunded_item_id', $refund_item_id );
break;
case 'fee' :
$fee = new stdClass();
$fee->name = $order_items[ $refund_item_id ]['name'];
$fee->tax_class = $order_items[ $refund_item_id ]['tax_class'];
$fee->taxable = $fee->tax_class !== '0';
$fee->amount = wc_format_refund_total( $refund_item['refund_total'] );
$fee->tax = wc_format_refund_total( array_sum( $refund_item['refund_tax'] ) );
$fee->tax_data = array_map( 'wc_format_refund_total', $refund_item['refund_tax'] );
$new_item_id = $refund->add_fee( $fee );
wc_add_order_item_meta( $new_item_id, '_refunded_item_id', $refund_item_id );
break;
}
}
}
$refund->update_taxes();
$refund->calculate_totals( false );
}
}
return new WC_Order_Refund( $refund_id );
}
/**
* Get tax class by tax id.
*
* @since 2.2
* @param int $tax_id
* @return string
*/
function wc_get_tax_class_by_tax_id( $tax_id ) {
global $wpdb;
$tax_class = $wpdb->get_var( $wpdb->prepare( "SELECT tax_rate_class FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %d", $tax_id ) );
return wc_clean( $tax_class );
}
/**
* Get payment gateway class by order data.
*
* @since 2.2
* @param int|WC_Order $order
* @return WC_Payment_Gateway|bool
*/
function wc_get_payment_gateway_by_order( $order ) {
if ( WC()->payment_gateways() ) {
$payment_gateways = WC()->payment_gateways->payment_gateways();
} else {
$payment_gateways = array();
}
if ( is_object( $order ) ) {
$payment_method = $order->payment_method;
} else {
$order_id = absint( $order );
$order = new WC_Order( $order_id );
$payment_method = $order->payment_method;
}
return isset( $payment_gateways[ $order->payment_method ] ) ? $payment_gateways[ $order->payment_method ] : false;
}

View File

@ -143,7 +143,7 @@ function wc_update_new_customer_past_orders( $customer_id ) {
$customer_orders = get_posts( array(
'numberposts' => -1,
'post_type' => 'shop_order',
'post_type' => wc_get_order_types(),
'post_status' => array_keys( wc_get_order_statuses() ),
'fields' => 'ids',
'meta_query' => array(

View File

@ -17,7 +17,7 @@ $customer_orders = get_posts( apply_filters( 'woocommerce_my_account_my_orders_q
'numberposts' => $order_count,
'meta_key' => '_customer_user',
'meta_value' => get_current_user_id(),
'post_type' => 'shop_order',
'post_type' => wc_get_order_types( 'view-orders' ),
'post_status' => array_keys( wc_get_order_statuses() )
) ) );

View File

@ -48,7 +48,7 @@ $wpdb->query("DELETE FROM $wpdb->options WHERE option_name LIKE 'woocommerce_%';
if ( ! empty( $status_options['uninstall_data'] ) ) {
// Delete posts + data
$wpdb->query( "DELETE FROM {$wpdb->posts} WHERE post_type IN ( 'product', 'product_variation', 'shop_coupon', 'shop_order' );" );
$wpdb->query( "DELETE FROM {$wpdb->posts} WHERE post_type IN ( 'product', 'product_variation', 'shop_coupon', 'shop_order', 'shop_order_refund' );" );
$wpdb->query( "DELETE FROM {$wpdb->postmeta} meta LEFT JOIN {$wpdb->posts} posts ON posts.ID = meta.post_id WHERE wp.ID IS NULL;" );
$wpdb->query( "DROP TABLE IF EXISTS " . $wpdb->prefix . "woocommerce_order_items" );
$wpdb->query( "DROP TABLE IF EXISTS " . $wpdb->prefix . "woocommerce_order_itemmeta" );