In WooCommerce there's regular price X and sales price Y.
I would like to add a specific coupon with a code for a 50 discount to be taken from the regular price X.
I would like the coupon to disregard the sale price so I get X-50 NOT Y-50. But when the specific coupon is not applied price Y is used.
I found the following which works for all coupons, but I need the solution to work for a specific coupon:
add_action( 'woocommerce_before_calculate_totals', 'add_custom_price', 10, 1);
function add_custom_price( $cart_object) {
global $woocommerce;
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$coupon = False;
if ($coupons = WC()->cart->get_applied_coupons() == False )
$coupon = False;
else {
foreach ( WC()->cart->get_applied_coupons() as $code ) {
$coupons1 = new WC_Coupon( $code );
if ($coupons1->type == 'percent_product' || $coupons1->type == 'percent')
$coupon = True;
}
}
if ($coupon == True)
foreach ( $cart_object->get_cart() as $cart_item )
{
$price = $cart_item['data']->regular_price;
$cart_item['data']->set_price( $price );
}
}
Related
Hello what is the hook to send an email when the order is moved to the trash?
I have this code that works when the order is canceled or fails but I also need to send an email when the order is moved to the trash.
add_action('woocommerce_order_status_changed', 'send_custom_email_notifications', 10, 4 );
function send_custom_email_notifications( $order_id, $old_status, $new_status, $order ){
if ( $new_status == 'cancelled' || $new_status == 'failed' ){
$wc_emails = WC()->mailer()->get_emails(); // Get all WC_emails objects instances
$customer_email = $order->get_billing_email(); // The customer email
}
if ( $new_status == 'cancelled' ) {
// change the recipient of this instance
$wc_emails['WC_Email_Cancelled_Order']->recipient = $customer_email;
// Sending the email from this instance
$wc_emails['WC_Email_Cancelled_Order']->trigger( $order_id );
}
elseif ( $new_status == 'failed' ) {
// change the recipient of this instance
$wc_emails['WC_Email_Failed_Order']->recipient = $customer_email;
// Sending the email from this instance
$wc_emails['WC_Email_Failed_Order']->trigger( $order_id );
}
}
Try this:
add_action('woocommerce_order_status_changed', 'send_custom_email_notifications', 10, 4 );
function send_custom_email_notifications( $order_id, $old_status, $new_status, $order ){
if ( $new_status == 'cancelled' || $new_status == 'failed' || 'trash' == get_post_meta($order_id, 'post_status', true) ){ //added extra condition here
$wc_emails = WC()->mailer()->get_emails(); // Get all WC_emails objects instances
$customer_email = $order->get_billing_email(); // The customer email
}
if ( $new_status == 'cancelled' ) {
// change the recipient of this instance
$wc_emails['WC_Email_Cancelled_Order']->recipient = $customer_email;
// Sending the email from this instance
$wc_emails['WC_Email_Cancelled_Order']->trigger( $order_id );
}
elseif ( $new_status == 'failed' ) {
// change the recipient of this instance
$wc_emails['WC_Email_Failed_Order']->recipient = $customer_email;
// Sending the email from this instance
$wc_emails['WC_Email_Failed_Order']->trigger( $order_id );
}
elseif ( 'trash' == get_post_meta($order_id, 'post_status', true) ) {
// change the recipient of this instance
$wc_emails['WC_Email_Failed_Order']->recipient = $customer_email;
// Sending the email from this instance
$wc_emails['WC_Email_Failed_Order']->trigger( $order_id ); //trigger some email here
}
}
I'm using "Woo estimated shipping date" plugin to sell pre-order products with estimated shipping date but the pluging show the message plus the date, and I need to show only the message not the "06/04/2022:
That is given by the product page editor option in "Estimated Delivery Time in Days":
Here's the plugin code:
<?php
namespace Saimon\WCESD\Views;
use Saimon\WCESD\Date_Calculator;
use Saimon\WCESD\Helper;
defined( 'ABSPATH' ) || exit;
class Single_Product {
public function __construct() {
$this->hooks();
}
private function hooks() {
add_action( 'woocommerce_after_add_to_cart_form', [ self::class, 'show_date' ] );
}
public static function show_date() {
if ( 'yes' !== Helper::get_option( 'wc_esd_date_enable' ) ) {
return;
}
$wc_esd_date = Helper::get_option( 'wc_esd_date' );
$wc_esd_date = $wc_esd_date ? $wc_esd_date : 5;
$wc_esd_date_message = Helper::get_option( 'wc_esd_date_message' );
$wc_esd_date_message = $wc_esd_date_message ? $wc_esd_date_message : __( 'Estimated Delivery Date', 'wcesd' );
$today = strtotime( current_time( 'mysql' ) );
$to_date = '';
if ( Helper::is_weekend_excluded() ) {
$date = ( new Date_Calculator( $today, $wc_esd_date ) )->get_date();
if ( Helper::is_date_range_enabled() ) {
$wc_esd_date = $wc_esd_date + Helper::get_date_range_gap();
$to_date = ( new Date_Calculator( $today, $wc_esd_date ) )->get_date();
}
} else {
$date = ( new Date_Calculator( $today, $wc_esd_date, false ) )->get_date();
if ( Helper::is_date_range_enabled() ) {
$wc_esd_date = $wc_esd_date + Helper::get_date_range_gap();
$to_date = ( new Date_Calculator( $today, $wc_esd_date ) )->get_date();
}
}
if ( ! empty( $to_date ) ) {
$message = $wc_esd_date_message . ' ' . Helper::display_date( $date ) . ' - ' . Helper::display_date( $to_date );
} else {
$message = $wc_esd_date_message . ' ' . Helper::display_date( $date );
}
$html = '<div class="wesd-box">';
$html .= '<strong class="shipper-date">';
$html .= $message;
$html .= '</strong>';
$html .= '</div>';
echo wp_kses_post(
$html
);
}
}
And I need to achieve this:
The problem is if I don't put a day in the "Estimated delivery time in days" field, the system use a default 5 days time and put the date again (06/04/2022) again.
Any idea how to achieve this guys? Thank you very much.
below is my Apex Trigger. I am a beginner and trying to write its test class but continuously getting error "System.DmlException: Insert failed. First exception on row 0; first error: REQUIRED_FIELD_MISSING, Error: You can't select products until you've chosen a price book for this opportunity on the products related list.: []".
trigger TrgrOptyHighestCustmorePrice on Opportunity (before insert, before update)
{
public Id oid;
public String bidType;
public String BUCode;
for(Opportunity o : trigger.new)
{
oid = o.Id;
bidType = o.BidType__c;
BUCode = o.Business_Line_BU__c;
}
List<OpportunityLineItem> oliList = new list<OpportunityLineItem>([SELECT id, Customer_Price__c, ReCat_Product_Line__c
FROM OpportunityLineItem
WHERE OpportunityId =: oid ORDER BY
Customer_Price__c DESC LIMIT 1]);
for(OpportunityLineItem oli : oliList)
{
if(bidType == 'Competitive' && oli.ReCat_Product_Line__c == 'DMS')
{
BUCode = 'BL.619';
}
if(bidType == 'Competitive' && (oli.ReCat_Product_Line__c == 'EMS' || oli.ReCat_Product_Line__c == 'GMS'))
{
BUCode = 'BL.620';
}
if(bidType == 'Competitive' && oli.ReCat_Product_Line__c == 'MMS')
{
BUCode = 'BL.622';
}
if(bidType == 'Sole Sourced' && oli.ReCat_Product_Line__c == 'DMS')
{
BUCode = 'BL.624';
}
if(bidType == 'Sole Sourced' && (oli.ReCat_Product_Line__c == 'EMS' || oli.ReCat_Product_Line__c == 'GMS'))
{
BUCode = 'BL.621';
}
if(bidType == 'Sole Sourced' && oli.ReCat_Product_Line__c == 'MMS')
{
BUCode = 'BL.623';
}
}
for(Opportunity opt : trigger.new)
{
opt.Business_Line_BU__c = BUCode;
}
}
Test Class
#isTest(seeAllData=true)
public class Test_TrgrOptyHighestCustmorePrice {
private static testmethod void TrgrOptyHighestCustmorePriceTest(){
Test.startTest();
//Insert a test product.
Product2 p1 = new Product2(Name='Product Monthly 1111', isActive=true, CurrencyIsoCode='USD', ReCat_Product_Line__c = 'DMS');
insert p1;
// Get standard price book ID.
Id pricebookId = Test.getStandardPricebookId();
// Insert a price book entry for the standard price book.
PricebookEntry standardPrice = new PricebookEntry(
Pricebook2Id = pricebookId, Product2Id = p1.Id,
UnitPrice = 10000, IsActive = true);
insert standardPrice;
Pricebook2 customPB = new Pricebook2(Name='Custom Pricebook', isActive=true);
insert customPB;
PricebookEntry customPrice = new PricebookEntry(
Pricebook2Id = customPB.Id, Product2Id = p1.Id,
UnitPrice = 12000, IsActive = true);
insert customPrice;
// Insert Opportunity
Opportunity opt = new Opportunity(Name='Test',StageName='Prospect',
CloseDate=date.today(),BidType__c = 'Competitive',
Business_Line_BU__c = 'BL.619',
PriceBook2 = customPB);
insert opt;
OpportunityLineItem optLI = new OpportunityLineItem(OpportunityId = opt.id, Product2Id = p1.Id);
insert optLI;
update opt;
Test.stopTest();
}
}
I am unable to understand how can I test my simple trigger.
Its because u do not fill all required fields for the Opportunity Line Item. See: https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_objects_opportunitylineitem.htm for required fields.
This as an example will work:
OpportunityLineItem optLI = new OpportunityLineItem(OpportunityId = opt.id, Product2Id = p1.Id, TotalPrice = 100, PricebookEntryId=customPrice.Id, Quantity =3);
First Insert the opportunity.
Then update the opportunity with the pricebookid.
// Insert Opportunity
Opportunity opt = new Opportunity(Name='Test',StageName='Prospect',
CloseDate=date.today(),BidType__c = 'Competitive',
Business_Line_BU__c = 'BL.619'
);
insert opt;
opt.PriceBook2 = customPB;
update opt;
Paypal in laravel keep returning maximum 30 seconds timeout, sometime it can proceed smoothly but when cart product increase, it will keep return this error, and sometime the error is when create payment, sometime is execute payment, extremely not stable, how can i solve this? i have tried extend the timeout setting to 300, but it still return me a timeout error.
here is my create payment code:
$item_array = [];
$shipping = $request->shipping;
$tax = $request->tax;
$tax_amount = 0;
$subtotal = $total = 0;
$currency = "MYR";
$payer = new Payer();
$payer->setPaymentMethod("paypal");
$credential = new OAuthTokenCredential(env('PAYPAL_SANDBOX_CLIENT_ID'), env('PAYPAL_SANDBOX_SECRET'));
$apiContext = new ApiContext($credential, null);
$order = Order::findOrFail($id);
// change order product status
foreach ($order->orderProduct as $order_product_key => $order_product) {
// get variant
$variant_title_array = array();
if (count($order_product->variantValue) > 0) {
foreach ($order_product->variantValue->variantOption as $variant_option) {
array_push($variant_title_array, $variant_option->name);
}
}
$variant= "";
if (count($variant_title_array) > 0) {
$variant = " ( ".implode(', ', $variant_title_array)." )";
}
// calculate product price and promotion price
$product_price = $compare_price = "";
$product_promotion = get_cart_product_promotion ($order_product, $order);
$product_price = get_product_price_in_cart ($order_product);
// if promotion exits
if (count($product_promotion) != 0) {
$compare_price = get_product_price_in_cart ($order_product);
$product_price = calculate_product_price_after_promotion ($compare_price, $product_promotion);
}
$item = new Item();
$item->setName($order_product->product->title . $variant)
->setCurrency($currency)
->setQuantity($order_product->quantity)
->setSku(get_product_sku_in_cart ($order_product)) // Similar to `item_number` in Classic API
->setPrice((float) str_replace('RM ','', $product_price));
$item_array[$order_product_key] = $item;
$subtotal += (float) str_replace('RM ','', $product_price) * $order_product->quantity;
}
// calculate tax
$tax_amount = ($subtotal * $tax) / 100;
$itemList = new ItemList();
$itemList->setItems($item_array);
$shipping_address = new ShippingAddress();
$shipping_address->setCity('City')
->setCountryCode('AR')
->setPostalCode('200')
->setLine1('Adress Line1')
->setState('State')
->setRecipientName('Recipient Name');
$details = new Details();
$details->setShipping($shipping)
->setTax($tax_amount)
->setSubtotal($subtotal);
$total = $subtotal + $shipping + $tax_amount;
$amount = new Amount();
$amount->setCurrency($currency)
->setTotal($total)
->setDetails($details);
$transaction = new Transaction();
$transaction->setAmount($amount)
->setItemList($itemList)
->setDescription("Payment description")
->setInvoiceNumber(uniqid());
$baseUrl = url('/');
$redirectUrls = new RedirectUrls();
$redirectUrls->setReturnUrl("$baseUrl/ExecutePayment.php?success=true")
->setCancelUrl("$baseUrl/ExecutePayment.php?success=false");
$payment = new Payment();
$payment->setIntent("sale")
->setPayer($payer)
->setRedirectUrls($redirectUrls)
->setTransactions(array($transaction));
$request = clone $payment;
try {
$payment->create($apiContext);
} catch (PayPalConnectionException $ex) {
echo $ex->getCode(); // Prints the Error Code
echo $ex->getData(); // Prints the detailed error message
die($ex);
} catch (Exception $ex) {
die($ex);
}
$approvalUrl = $payment->getApprovalLink();
$response = array(
'paymentID' => $payment->id
);
return json_encode($response);
here is my execute payment code:
$shipping = $request->shipping;
$tax = $request->tax;
$tax_amount = 0;
$subtotal = $total = 0;
$currency = "MYR";
$credential = new OAuthTokenCredential(env('PAYPAL_SANDBOX_CLIENT_ID'), env('PAYPAL_SANDBOX_SECRET'));
$apiContext = new ApiContext($credential, null);
$paymentId = $request->paymentID;
$payment = Payment::get($paymentId, $apiContext);
$transaction = new Transaction();
$amount = new Amount();
$details = new Details();
$order = Order::findOrFail($id);
// store order address
$order_address = OrderAddress::firstOrCreate(
[
'order_id' => $order->id
],
[
'name' => $request->shipping_name ,
'phone' => $request->shipping_phone ,
'address1' => $request->shipping_address1 ,
'address2' => $request->shipping_address2 ,
'postcode' => $request->shipping_postcode ,
'state' => $request->shipping_state ,
'country' => $request->shipping_country ,
'city' => $request->shipping_city ,
'order_id' => $order->id
]
);
// update address if exist
$order_address->update([
'name' => $request->shipping_name ,
'phone' => $request->shipping_phone ,
'address1' => $request->shipping_address1 ,
'address2' => $request->shipping_address2 ,
'postcode' => $request->shipping_postcode ,
'state' => $request->shipping_state ,
'country' => $request->shipping_country ,
'order_id' => $order->id
]);
// change order product status
foreach ($order->orderProduct as $order_product) {
// calculate product price and promotion price
$product_price = $compare_price = "";
$product_promotion = get_cart_product_promotion ($order_product, $order);
$product_price = get_product_price_in_cart ($order_product);
// if promotion exits
if (count($product_promotion) != 0) {
$compare_price = get_product_price_in_cart ($order_product);
$product_price = calculate_product_price_after_promotion ($compare_price, $product_promotion);
}
$product_price = (float) str_replace("RM ","",$product_price);
// add promotion to order product if promotion exist
if ($compare_price != "") {
$order_product->order_promotion_id = $order->orderPromotion->promotion_id;
}
$order_product->price = $product_price;
$order_product->status = 2;
$subtotal += $product_price * $order_product->quantity;
$order_product->save();
}
// calculate tax
$tax_amount = ($subtotal * $tax) / 100;
// change cart detail
$current_date_time = Carbon::now();
$order->update([
'subtotal' => $subtotal,
'status' => 2,
'submited_on' => $current_date_time,
'payment_method' => "paypal"
]);
// update shipping fees
if ($shipping > 0) {
$order->shipping_fees = $shipping;
}
// update tax
if ($tax > 0) {
$order->tax = ($subtotal * $tax) / 100;
}
$order->save();
// paypal settings
$total = $subtotal + $shipping + $tax_amount;
$details->setShipping($shipping)
->setTax($tax_amount)
->setSubtotal($subtotal);
$amount->setCurrency($currency);
$amount->setTotal($total);
$amount->setDetails($details);
$transaction->setAmount($amount);
// Add the above transaction object inside our Execution object.
$execution->addTransaction($transaction);
try {
$result = $payment->execute($execution, $apiContext);
try {
$payment = Payment::get($paymentId, $apiContext);
} catch (Exception $ex) {
exit(1);
}
} catch (Exception $ex) {
exit(1);
}
echo "success";
I have a document in Google Sheets (I work in healthcare simulation) that has two separate sheets (tabs) within the master. One tab is MAR, the other is VITALS. I need each one to run from within the same script and not interfere with each other. I can only get one to work, not the other.
I will post each one below (you will be able to see that when one works, the other does not but each WILL work when the other is //rem'd out).
I am not sure which variables to change to have them coexist and work together. I know I must be missing something simple. THANK YOU in advance!
MAR TIME STAMP
function onEdit() {
var x = SpreadsheetApp.getActiveSheet();
if( x.getName() == "MAR" ) { //checks that we're on the correct sheet
var y = x.getActiveCell();
if( y.getColumn() == 4 ) { //checks the column
var nextCell = y.offset(0,1);
if( nextCell.getValue() === '' ) //is empty?
nextCell.setValue(new Date());
}
}
}
VITALS TIME STAMP
function onEdit() {
var x = SpreadsheetApp.getActiveSheet();
if( x.getName() == "Vitals" ) { //checks that we're on the correct sheet
var y = x.getActiveCell();
if( y.getColumn() == 1 ) { //checks the column
var nextCell = y.offset(0,1);
if( nextCell.getValue() === '' ) //is empty?
nextCell.setValue(new Date());
}
}
}
How about this?
function onEdit() {
var x = SpreadsheetApp.getActiveSheet();
if( x.getName() == "MAR" ) { //checks that we're on the correct sheet
var y = x.getActiveCell();
if( y.getColumn() == 4 ) { //checks the column
var nextCell = y.offset(0,1);
if( nextCell.getValue() === '' ) //is empty?
nextCell.setValue(new Date());
}
}
if( x.getName() == "Vitals" ) { //checks that we're on the correct sheet
var y = x.getActiveCell();
if( y.getColumn() == 1 ) { //checks the column
var nextCell = y.offset(0,1);
if( nextCell.getValue() === '' ) //is empty?
nextCell.setValue(new Date());
}
}
}
Or...
function onEdit(e) {
var sh, sheets, cols, sheetInd, o;
sh = e.source.getActiveSheet()
sheets = ["MAR", "Vitals"]
cols = [4, 1]
sheetInd = sheets.indexOf(sh.getName())
if(sheetInd == -1 || cols[sheetInd !== e.range.columnStart]) return;
o = e.range.offset(0, 1)
if(!o.getValue()) o.setValue(new Date())
}