public function to_html()
    {
        /**
         * Provide a customized invoice.
         *
         * @since  1.0.0
         */
        $html = apply_filters('ms_shortcode_custom_invoice', '', $this->data);
        if (!empty($html)) {
            return $html;
        } else {
            $html = '';
        }
        $invoice = $this->data['invoice'];
        $member = $this->data['member'];
        $subscription = $this->data['ms_relationship'];
        $membership = $this->data['membership'];
        $gateway = $this->data['gateway'];
        $is_free = false;
        $invoice_number = $invoice->get_invoice_number();
        $inv_title = sprintf('<a href="%s">%s</a>', get_permalink($invoice->id), esc_html(__('Invoice ', MS_TEXT_DOMAIN) . $invoice_number));
        if ($invoice->amount > 0) {
            $inv_amount = sprintf('%1$s %2$s', $invoice->currency, MS_Helper_Billing::format_price($invoice->amount));
        } else {
            $inv_amount = __('Free', MS_TEXT_DOMAIN);
            $is_free = true;
        }
        if ($invoice->tax) {
            $inv_taxes = sprintf('%s %s', $invoice->currency, MS_Helper_Billing::format_price($invoice->tax));
        } else {
            $inv_taxes = '';
        }
        if ($invoice->discount) {
            $inv_discount = sprintf('%s -%s', $invoice->currency, MS_Helper_Billing::format_price($invoice->discount));
        } else {
            $inv_discount = '';
        }
        if ($invoice->pro_rate) {
            $inv_pro_rate = sprintf('%s -%s', $invoice->currency, MS_Helper_Billing::format_price($invoice->pro_rate));
        } else {
            $inv_pro_rate = '';
        }
        $inv_total = sprintf('%s %s', $invoice->currency, MS_Helper_Billing::format_price($invoice->total));
        $inv_title = apply_filters('ms_invoice_title', $inv_title, $invoice);
        $inv_from = apply_filters('ms_invoice_sender', MS_Plugin::instance()->settings->invoice_sender_name, $invoice);
        $inv_to = apply_filters('ms_invoice_recipient', $member->username, $invoice, $member);
        $inv_status = apply_filters('ms_invoice_status', $invoice->status_text(), $invoice);
        $inv_item_name = apply_filters('ms_invoice_item_name', $membership->name, $invoice, $membership);
        $inv_amount = apply_filters('ms_invoice_amount', $inv_amount, $invoice);
        $inv_taxes = apply_filters('ms_invoice_taxes', $inv_taxes, $invoice);
        $inv_discount = apply_filters('ms_invoice_discount', $inv_discount, $invoice);
        $inv_pro_rate = apply_filters('ms_invoice_pro_rate', $inv_pro_rate, $invoice);
        $inv_total = apply_filters('ms_invoice_total', $inv_total, $invoice);
        $inv_details = apply_filters('ms_invoice_description', $invoice->description, $invoice, null);
        $inv_date = apply_filters('ms_invoice_date', MS_Helper_Period::format_date($invoice->invoice_date), $invoice, null);
        $inv_due_date = apply_filters('ms_invoice_due_date', MS_Helper_Period::format_date($invoice->due_date), $invoice, null);
        if ($invoice->uses_trial) {
            $trial_date = apply_filters('ms_invoice_trial_date', MS_Helper_Period::get_period_desc($membership->trial_period, true), $trial_invoice, $invoice);
            $trial_date .= sprintf(' <small>(%s %s)</small>', __('ends on', MS_TEXT_DOMAIN), MS_Helper_Period::format_date($invoice->trial_ends));
        } else {
            $trial_date = '';
        }
        ob_start();
        ?>
		<div class="entry-content ms-invoice" id="invoice">
			<?php 
        /**
         * We hardcode the CSS styles into this file, because the shortcode
         * is also used in Emails, which usually do not load remote CSS
         * files by default...
         */
        ?>
			<style>
			#invoice table, th, td { margin: 0; font-size: 14px; }
			#invoice table { padding: 0; width: 520px; border: 1px solid #DDD; background-color: #FFF; box-shadow: 0 1px 8px #F0F0F0; }
			#invoice th, td { border: 0; padding: 8px; }
			#invoice th { font-weight: bold; text-align: left; text-transform: none; font-size: 13px; }
			#invoice tr.alt { background-color: #F9F9F9; }
			#invoice tr.sep th,
			#invoice tr.sep td { border-top: 1px solid #DDD; padding-top: 16px; }
			#invoice tr.space th,
			#invoice tr.space td { padding-bottom: 16px; }
			#invoice tr.ms-inv-sep th,
			#invoice tr.ms-inv-sep td { line-height: 1px; height: 1px; padding: 0; border-bottom: 1px solid #DDD; background-color: #F9F9F9; }
			#invoice .ms-inv-total .ms-inv-price { font-weight: bold; font-size: 18px; text-align: right; }
			#invoice h2 { text-align: right; padding: 10px 10px 0 0; }
			#invoice h2 a { color: #000; }
			<?php 
        do_action('ms_invoice_css');
        ?>
			</style>

			<div class="ms-invoice-details ms-status-<?php 
        echo esc_attr($invoice->status);
        ?>
">
				<table class="ms-purchase-table">
					<tr class="ms-inv-title">
						<td colspan="2"><h2><?php 
        echo $inv_title;
        ?>
</h2></td>
					</tr>

					<?php 
        if (!empty($inv_from)) {
            ?>
						<tr class="ms-inv-from">
							<th><?php 
            _e('Sender', MS_TEXT_DOMAIN);
            ?>
</th>
							<td class="ms-inv-text"><?php 
            echo $inv_from;
            ?>
</td>
						</tr>
					<?php 
        }
        ?>

					<tr class="ms-inv-to">
						<th><?php 
        _e('Invoice to', MS_TEXT_DOMAIN);
        ?>
</th>
						<td class="ms-inv-text"><?php 
        echo $inv_to;
        ?>
</td>
					</tr>
					<tr class="ms-inv-invoice-date">
						<th><?php 
        _e('Invoice date', MS_TEXT_DOMAIN);
        ?>
</th>
						<td class="ms-inv-date"><?php 
        echo $inv_date;
        ?>
</td>
					</tr>
					<?php 
        if (!empty($trial_date)) {
            ?>
						<tr class="ms-inv-trial-end-date">
							<th><?php 
            _e('Trial period', MS_TEXT_DOMAIN);
            ?>
</th>
							<td class="ms-inv-date"><?php 
            echo $trial_date;
            ?>
</td>
						</tr>
					<?php 
        }
        ?>
					<tr class="ms-inv-status space">
						<th><?php 
        _e('Status', MS_TEXT_DOMAIN);
        ?>
</th>
						<td class="ms-inv-text"><?php 
        echo $inv_status;
        ?>
</td>
					</tr>
					<tr class="ms-inv-item-name alt sep">
						<th><?php 
        _e('Name', MS_TEXT_DOMAIN);
        ?>
</th>
						<td class="ms-inv-text"><?php 
        echo $inv_item_name;
        ?>
</td>
					</tr>

					<?php 
        if (!empty($inv_details)) {
            ?>
					<tr class="ms-inv-description alt">
						<th><?php 
            _e('Description', MS_TEXT_DOMAIN);
            ?>
</th>
						<td class="ms-inv-text"><?php 
            echo $inv_details;
            ?>
</td>
					</tr>
					<?php 
        }
        ?>

					<tr class="ms-inv-amount alt space">
						<th><?php 
        _e('Amount', MS_TEXT_DOMAIN);
        ?>
</th>
						<td class="ms-inv-price"><?php 
        echo $inv_amount;
        ?>
</td>
					</tr>

					<?php 
        $sep = 'sep';
        ?>

					<?php 
        if (!empty($inv_discount)) {
            ?>
						<tr class="ms-inv-discount <?php 
            echo esc_attr($sep);
            $sep = '';
            ?>
">
							<th><?php 
            _e('Coupon discount', MS_TEXT_DOMAIN);
            ?>
</th>
							<td class="ms-inv-price"><?php 
            echo $inv_discount;
            ?>
</td>
						</tr>
					<?php 
        }
        ?>

					<?php 
        if (!empty($inv_pro_rate)) {
            ?>
						<tr class="ms-inv-pro-rate <?php 
            echo esc_attr($sep);
            $sep = '';
            ?>
">
							<th><?php 
            _e('Pro rate discount', MS_TEXT_DOMAIN);
            ?>
</th>
							<td class="ms-inv-price"><?php 
            echo $inv_pro_rate;
            ?>
</td>
						</tr>
					<?php 
        }
        ?>

					<?php 
        if (!empty($inv_taxes)) {
            ?>
						<tr class="ms-inv-tax <?php 
            echo esc_attr($sep);
            $sep = '';
            ?>
">
							<th><?php 
            printf(__('Taxes %s', MS_TEXT_DOMAIN), '<small>(' . $invoice->tax_name . ')</small>');
            ?>
</th>
							<td class="ms-inv-price"><?php 
            echo $inv_taxes;
            ?>
</td>
						</tr>
					<?php 
        }
        ?>

					<?php 
        if (!$is_free) {
            ?>
						<tr class="ms-inv-due-date <?php 
            echo esc_attr($sep);
            $sep = '';
            ?>
">
							<th><?php 
            _e('Payment due', MS_TEXT_DOMAIN);
            ?>
</th>
							<td class="ms-inv-date"><?php 
            echo $inv_due_date;
            ?>
</td>
						</tr>
					<?php 
        }
        ?>
					<tr class="ms-inv-total <?php 
        echo esc_attr($sep);
        $sep = '';
        ?>
">
						<th><?php 
        _e('Total', MS_TEXT_DOMAIN);
        ?>
</th>
						<td class="ms-inv-price"><?php 
        echo $inv_total;
        ?>
</td>
					</tr>

					<?php 
        $show_button = lib2()->is_true($this->data['pay_button']);
        if ($invoice->is_paid()) {
            // Invoice is already paid. We don't need a payment
            // button...
            $show_button = false;
        }
        if ($show_button) {
            ?>
						<tr class="ms-inv-sep sep"><td colspan="2"></td></tr>
						<?php 
            do_action('ms_view_shortcode_invoice_purchase_button', $subscription, $invoice);
        }
        ?>
				</table>
			</div>
		</div>
		<?php 
        $html = ob_get_clean();
        $html = apply_filters('ms_compact_code', $html);
        return apply_filters('ms_shortcode_invoice', $html, $this->data);
    }
 /**
  * Get current payment type description.
  *
  * Description to show in the admin list table.
  *
  * @since  1.0.0
  * @api
  *
  * @return string The current payment type description.
  */
 public function get_payment_type_desc()
 {
     $desc = __('N/A', 'membership2');
     $has_payment = !$this->is_free();
     switch ($this->payment_type) {
         case self::PAYMENT_TYPE_FINITE:
             if ($has_payment) {
                 $desc = sprintf(__('Pay for %1$s', 'membership2'), MS_Helper_Period::get_period_desc($this->period, true));
             } else {
                 $desc = sprintf(__('Free for %1$s', 'membership2'), MS_Helper_Period::get_period_desc($this->period, true));
             }
             break;
         case self::PAYMENT_TYPE_DATE_RANGE:
             if ($has_payment) {
                 $desc = sprintf(__('Pay from %1$s to %2$s', 'membership2'), $this->period_date_start, $this->period_date_end);
             } else {
                 $desc = sprintf(__('Free from %1$s to %2$s', 'membership2'), $this->period_date_start, $this->period_date_end);
             }
             break;
         case self::PAYMENT_TYPE_RECURRING:
             if ($has_payment) {
                 $desc = __('Pay each %1$s', 'membership2');
                 if (1 == $this->pay_cycle_repetitions) {
                     $desc = __('Single payment', 'membership2');
                 } elseif ($this->pay_cycle_repetitions > 1) {
                     $desc .= ', ' . __('%2$s payments', 'membership2');
                 }
             } else {
                 $desc = __('Free access', 'membership2');
             }
             $desc = sprintf($desc, MS_Helper_Period::get_period_desc($this->pay_cycle_period), $this->pay_cycle_repetitions);
             break;
         case self::PAYMENT_TYPE_PERMANENT:
         default:
             if ($has_payment) {
                 $desc = __('Single payment', 'membership2');
             } else {
                 $desc = __('Free access', 'membership2');
             }
             break;
     }
     return apply_filters('ms_model_membership_get_payment_type_desc', $desc, $this);
 }
 /**
  * Get textual payment information description.
  *
  * @since  1.0.0
  * @api
  *
  * @param  MS_Model_Invoice $invoice Optional. Specific invoice that defines
  *         the price. Default is the price defined in the membership.
  * @param  bool $short Optional. Default is false. If set to true then a
  *          hort sumary is returned
  * @return string The description.
  */
 public function get_payment_description($invoice = null, $short = false)
 {
     $currency = MS_Plugin::instance()->settings->currency;
     $membership = $this->get_membership();
     $desc = '';
     if (null !== $invoice) {
         $total_price = $invoice->total;
         // Includes Tax
         $trial_price = $invoice->trial_price;
         // Includes Tax
     } else {
         $total_price = $membership->total_price;
         // Excludes Tax
         $trial_price = $membership->trial_price;
         // Excludes Tax
     }
     $total_price = MS_Helper_Billing::format_price($total_price);
     $trial_price = MS_Helper_Billing::format_price($trial_price);
     $payment_type = $this->payment_type;
     if (!$payment_type) {
         $payment_type = $membership->payment_type;
     }
     switch ($payment_type) {
         case MS_Model_Membership::PAYMENT_TYPE_PERMANENT:
             if (0 == $total_price) {
                 if ($short) {
                     $lbl = __('Nothing (for ever)', 'membership2');
                 } else {
                     $lbl = __('You will pay nothing for permanent access.', 'membership2');
                 }
             } else {
                 if ($short) {
                     $lbl = __('<span class="price">%1$s %2$s</span> (for ever)', 'membership2');
                 } else {
                     $lbl = __('You will pay <span class="price">%1$s %2$s</span> for permanent access.', 'membership2');
                 }
             }
             $desc = sprintf($lbl, $currency, $total_price);
             break;
         case MS_Model_Membership::PAYMENT_TYPE_FINITE:
             if (0 == $total_price) {
                 if ($short) {
                     $lbl = __('Nothing (until %4$s)', 'membership2');
                 } else {
                     $lbl = __('You will pay nothing for access until %3$s.', 'membership2');
                 }
             } else {
                 if ($short) {
                     $lbl = __('<span class="price">%1$s %2$s</span> (until %4$s)', 'membership2');
                 } else {
                     $lbl = __('You will pay <span class="price">%1$s %2$s</span> for access until %3$s.', 'membership2');
                 }
             }
             $desc .= sprintf($lbl, $currency, $total_price, MS_Helper_Period::format_date($this->calc_expire_date($this->expire_date)), $this->calc_expire_date($this->expire_date));
             break;
         case MS_Model_Membership::PAYMENT_TYPE_DATE_RANGE:
             if (0 == $total_price) {
                 if ($short) {
                     $lbl = __('Nothing (%5$s - %6$s)', 'membership2');
                 } else {
                     $lbl = __('You will pay nothing for access from %3$s until %4$s.', 'membership2');
                 }
             } else {
                 if ($short) {
                     $lbl = __('<span class="price">%1$s %2$s</span> (%5$s - %6$s)', 'membership2');
                 } else {
                     $lbl = __('You will pay <span class="price">%1$s %2$s</span> to access from %3$s until %4$s.', 'membership2');
                 }
             }
             $desc .= sprintf($lbl, $currency, $total_price, MS_Helper_Period::format_date($membership->period_date_start), MS_Helper_Period::format_date($membership->period_date_end), $membership->period_date_start, $membership->period_date_end);
             break;
         case MS_Model_Membership::PAYMENT_TYPE_RECURRING:
             if (1 == $membership->pay_cycle_repetitions) {
                 // Exactly 1 payment. Actually same as the "finite" type.
                 if ($short) {
                     $lbl = __('<span class="price">%1$s %2$s</span> (once)', 'membership2');
                 } else {
                     $lbl = __('You will pay <span class="price">%1$s %2$s</span> once.', 'membership2');
                 }
             } else {
                 if ($membership->pay_cycle_repetitions > 1) {
                     // Fixed number of payments (more than 1)
                     if ($short) {
                         $lbl = __('%4$s times <span class="price">%1$s %2$s</span> (each %3$s)', 'membership2');
                     } else {
                         $lbl = __('You will make %4$s payments of <span class="price">%1$s %2$s</span>, one each %3$s.', 'membership2');
                     }
                 } else {
                     // Indefinite number of payments
                     if ($short) {
                         $lbl = __('<span class="price">%1$s %2$s</span> (each %3$s)', 'membership2');
                     } else {
                         $lbl = __('You will pay <span class="price">%1$s %2$s</span> each %3$s.', 'membership2');
                     }
                 }
             }
             $desc .= sprintf($lbl, $currency, $total_price, MS_Helper_Period::get_period_desc($membership->pay_cycle_period), $membership->pay_cycle_repetitions);
             break;
     }
     if ($this->is_trial_eligible() && 0 != $total_price) {
         if (0 == absint($trial_price)) {
             if ($short) {
                 if (MS_Model_Membership::PAYMENT_TYPE_RECURRING == $payment_type) {
                     $lbl = __('after %4$s', 'membership2');
                 } else {
                     $lbl = __('on %4$s', 'membership2');
                 }
             } else {
                 $trial_price = __('nothing', 'membership2');
                 $lbl = __('The trial period of %1$s is for free.', 'membership2');
             }
         } else {
             $trial_price = MS_Helper_Billing::format_price($trial_price);
             $lbl = __('For the trial period of %1$s you only pay <span class="price">%2$s %3$s</span>.', 'membership2');
         }
         $desc .= sprintf(' <br />' . $lbl, MS_Helper_Period::get_period_desc($membership->trial_period, true), $currency, $trial_price, MS_Helper_Period::format_date($invoice->due_date, __('M j', 'membership2')));
     }
     return apply_filters('ms_model_relationship_get_payment_description', $desc, $membership, $payment_type, $this, $invoice, $short);
 }
 /**
  * Get current payment type description.
  *
  * Description to show in the admin list table.
  *
  * @since  1.0.0
  * @api
  *
  * @return string The current payment type description.
  */
 public function get_payment_type_desc()
 {
     $desc = __('N/A', MS_TEXT_DOMAIN);
     $has_payment = !$this->is_free();
     switch ($this->payment_type) {
         case self::PAYMENT_TYPE_FINITE:
             $desc = sprintf(__('For %1$s', MS_TEXT_DOMAIN), MS_Helper_Period::get_period_desc($this->period));
             break;
         case self::PAYMENT_TYPE_DATE_RANGE:
             $desc = sprintf(__('From %1$s to %2$s', MS_TEXT_DOMAIN), $this->period_date_start, $this->period_date_end);
             break;
             // RECURRING is PRO ONLY
         // RECURRING is PRO ONLY
         case self::PAYMENT_TYPE_PERMANENT:
         default:
             if ($has_payment) {
                 $desc = __('Single payment', MS_TEXT_DOMAIN);
             } else {
                 $desc = __('Permanent access', MS_TEXT_DOMAIN);
             }
             break;
     }
     return apply_filters('ms_model_membership_get_payment_type_desc', $desc, $this);
 }
 /**
  * Get textual payment information description.
  *
  * @since  1.0.0
  * @api
  *
  * @param  MS_Model_Invoice $invoice Optional. Specific invoice that defines
  *         the price. Default is the price defined in the membership.
  * @param  bool $short Optional. Default is false. If set to true then a
  *          hort sumary is returned
  * @return string The description.
  */
 public function get_payment_description($invoice = null, $short = false)
 {
     $currency = MS_Plugin::instance()->settings->currency;
     $membership = $this->get_membership();
     $desc = '';
     if (null !== $invoice) {
         $total_price = $invoice->total;
         // Includes Tax
         $trial_price = $invoice->trial_price;
         // Includes Tax
     } else {
         $total_price = $membership->total_price;
         // Excludes Tax
         $trial_price = $membership->trial_price;
         // Excludes Tax
     }
     $total_price = MS_Helper_Billing::format_price($total_price);
     $trial_price = MS_Helper_Billing::format_price($trial_price);
     $payment_type = $this->payment_type;
     if (!$payment_type) {
         $payment_type = $membership->payment_type;
     }
     switch ($payment_type) {
         case MS_Model_Membership::PAYMENT_TYPE_PERMANENT:
             if (0 == $total_price) {
                 if ($short) {
                     $lbl = __('Nothing (for ever)', MS_TEXT_DOMAIN);
                 } else {
                     $lbl = __('You will pay nothing for permanent access.', MS_TEXT_DOMAIN);
                 }
             } else {
                 if ($short) {
                     $lbl = __('<span class="price">%1$s %2$s</span> (for ever)', MS_TEXT_DOMAIN);
                 } else {
                     $lbl = __('You will pay <span class="price">%1$s %2$s</span> for permanent access.', MS_TEXT_DOMAIN);
                 }
             }
             $desc = sprintf($lbl, $currency, $total_price);
             break;
         case MS_Model_Membership::PAYMENT_TYPE_FINITE:
             if (0 == $total_price) {
                 if ($short) {
                     $lbl = __('Nothing (until %4$s)', MS_TEXT_DOMAIN);
                 } else {
                     $lbl = __('You will pay nothing for access until %3$s.', MS_TEXT_DOMAIN);
                 }
             } else {
                 if ($short) {
                     $lbl = __('<span class="price">%1$s %2$s</span> (until %4$s)', MS_TEXT_DOMAIN);
                 } else {
                     $lbl = __('You will pay <span class="price">%1$s %2$s</span> for access until %3$s.', MS_TEXT_DOMAIN);
                 }
             }
             $desc .= sprintf($lbl, $currency, $total_price, MS_Helper_Period::format_date($this->calc_expire_date($this->expire_date)), $this->calc_expire_date($this->expire_date));
             break;
         case MS_Model_Membership::PAYMENT_TYPE_DATE_RANGE:
             if (0 == $total_price) {
                 if ($short) {
                     $lbl = __('Nothing (%5$s - %6$s)', MS_TEXT_DOMAIN);
                 } else {
                     $lbl = __('You will pay nothing for access from %3$s until %4$s.', MS_TEXT_DOMAIN);
                 }
             } else {
                 if ($short) {
                     $lbl = __('<span class="price">%1$s %2$s</span> (%5$s - %6$s)', MS_TEXT_DOMAIN);
                 } else {
                     $lbl = __('You will pay <span class="price">%1$s %2$s</span> to access from %3$s until %4$s.', MS_TEXT_DOMAIN);
                 }
             }
             $desc .= sprintf($lbl, $currency, $total_price, MS_Helper_Period::format_date($membership->period_date_start), MS_Helper_Period::format_date($membership->period_date_end), $membership->period_date_start, $membership->period_date_end);
             break;
             // RECURRING is PRO ONLY
     }
     if ($this->is_trial_eligible() && 0 != $total_price) {
         if (0 == absint($trial_price)) {
             if ($short) {
                 // RECURRING is PRO ONLY
                 $lbl = __('on %4$s', MS_TEXT_DOMAIN);
             } else {
                 $trial_price = __('nothing', MS_TEXT_DOMAIN);
                 $lbl = __('The trial period of %1$s is for free.', MS_TEXT_DOMAIN);
             }
         } else {
             $trial_price = MS_Helper_Billing::format_price($trial_price);
             $lbl = __('For the trial period of %1$s you only pay <span class="price">%2$s %3$s</span>.', MS_TEXT_DOMAIN);
         }
         $desc .= sprintf(' <br />' . $lbl, MS_Helper_Period::get_period_desc($membership->trial_period, true), $currency, $trial_price, MS_Helper_Period::format_date($invoice->due_date, __('M j', MS_TEXT_DOMAIN)));
     }
     return apply_filters('ms_model_relationship_get_payment_description', $desc, $membership, $payment_type);
 }