diff --git a/modules/payment_method_po/payment_method_po.info b/modules/payment_method_po/payment_method_po.info
new file mode 100644
index 0000000..20ccf03
--- /dev/null
+++ b/modules/payment_method_po/payment_method_po.info
@@ -0,0 +1,6 @@
+name = Purchase Order Payment Method
+description = A purchase order payment method type that always successfully executes payments.
+core = 7.x
+dependencies[] = payment
+files[] = payment_method_po.module
+
diff --git a/modules/payment_method_po/payment_method_po.install b/modules/payment_method_po/payment_method_po.install
new file mode 100644
index 0000000..cf9715b
--- /dev/null
+++ b/modules/payment_method_po/payment_method_po.install
@@ -0,0 +1,103 @@
+<?php
+
+/**
+ * @file
+ * Installation and uninstallation functions.
+ */
+
+/**
+ * Implements hook_schema().
+ */
+function payment_method_po_schema() {
+  $schema['payment_method_po'] = array(
+    'fields' => array(
+      'message' => array(
+        'type' => 'text',
+        'size' => 'big',
+      ),
+      'pmid' => array(
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+        'default' => 0,
+      ),
+      'status' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+      ),
+      'text_format' => array(
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+      ),
+    ),
+    'primary key' => array('pmid'),
+    'unique keys' => array(
+      'pmid' => array('pmid'),
+    ),
+  );
+  $schema['payment_po'] = array(
+    'fields' => array(
+      'ppoid' => array(
+        'type' => 'serial',
+      ),
+      'pid' => array(
+        'description' => "The pid of this payment",
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'po_number' => array(
+        'description' => "The purchase order number supplied for this payment",
+        'type' => 'varchar',
+        'length' => 255,
+        'not null' => TRUE,
+      ),
+    ),
+    'foreign keys' => array(
+      'pid' => array(
+        'table' => 'payment',
+        'columns' => array(
+          'pid' => 'pid',
+        ),
+      ),
+    ),
+    'indexes' => array(
+      'pid' => array('pid'),
+    ),
+    'primary key' => array('ppoid'),
+  );
+  return $schema;
+}
+
+/**
+ * Implements hook_install().
+ */
+function payment_method_po_install() {
+  foreach (payment_method_po_payment_method_defaults() as $payment_method) {
+    entity_save('payment_method', $payment_method);
+  }
+}
+
+/**
+ * Returns default payment methods.
+ *
+ * @return array
+ *   An array of PaymentMethod objects.
+ */
+function payment_method_po_payment_method_defaults() {
+  $payment_methods[] = new PaymentMethod(array(
+    'controller' => payment_method_controller_load('PaymentMethodPOController'),
+    'controller_data' => array(
+      'message' => 'Supply your purchase order number for this payment',
+      'status' => PAYMENT_STATUS_PENDING,
+      'text_format' => 'plain_text',
+    ),
+    'name' => 'purchase_order',
+    'title_generic' => t('Purchase Order'),
+    'title_specific' => t('Purchase Order'),
+  ));
+
+  return $payment_methods;
+}
diff --git a/modules/payment_method_po/payment_method_po.module b/modules/payment_method_po/payment_method_po.module
new file mode 100644
index 0000000..09cbd85
--- /dev/null
+++ b/modules/payment_method_po/payment_method_po.module
@@ -0,0 +1,225 @@
+<?php
+
+/**
+ * @file
+ * Hook implementations and shared functions.
+ */
+/**
+ * Implements hook_payment_form_alter
+ */
+function payment_method_po_payment_form_alter(array &$elements, array &$form_state, array &$submit){
+  $payment = $form_state['payment'];
+  if(isset($payment->method) && $payment->method->name === 'purchase_order'){
+    //add a form element to get the purchase order number
+    $elements['po_number'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Purchase Order Number'),
+      '#description' => t('Please supply your purchase order number for this payment'),
+      '#size' => 60,
+      '#maxlength' => 255,
+      '#required' => TRUE,
+      '#weight' => 1
+    );
+  }
+  $submit[] = 'payment_method_po_payment_form_standalone_submit';
+}
+/**
+ * Submit handler added to payment_form_standalone
+ * @param array $form
+ * @param array $form_state
+ */
+function payment_method_po_payment_form_standalone_submit(array $form, array &$form_state){
+  //save the po_number in the payment object so that it can be saved once we have a payment id
+  $form_state['payment']->method->controller_data['po_number'] = $form_state['values']['po_number'];
+}
+/**
+ * Implements hook_payment_view_alter
+ */
+function payment_method_po_payment_view_alter(&$build){
+  //check if this payment was a purchase order payment and render the purchase order number
+  $payment = $build['#entity'];
+  $po_number = db_query("SELECT po_number from {payment_po} WHERE pid = :pid LIMIT 1", array(":pid" => $payment->pid))->fetchField();
+  if(!empty($po_number)){
+    $build['po_number'] = array(
+      '#markup' => '<div class="form-item form-type-item"><label>Purchase Order Number</label>' . $po_number. '</div>', 
+      '#weight' => 10
+    );
+  }
+}
+/**
+ * Implements hook_payment_method_controller_info().
+ */
+function payment_method_po_payment_method_controller_info() {
+  return array('PaymentMethodPOController');
+}
+
+/**
+ * Implements hook_entity_load().
+ */
+function payment_method_po_entity_load(array $entities, $entity_type) {
+if ($entity_type == 'payment_method') {
+    $pmids = array();
+    foreach ($entities as $payment_method) {
+      if ($payment_method->controller->name == 'PaymentMethodPOController') {
+        $pmids[] = $payment_method->pmid;
+      }
+    }
+    if ($pmids) {
+      $query = db_select('payment_method_po')
+        ->fields('payment_method_po')
+        ->condition('pmid', $pmids);
+      $result = $query->execute();
+      while ($data = $result->fetchAssoc()) {
+        $payment_method = $entities[$data['pmid']];
+        $payment_method->controller_data = (array) $data;
+        unset($payment_method->controller_data['pmid']);
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_ENTITY_TYPE_ACTION().
+ */
+function payment_method_po_payment_method_insert(PaymentMethod $payment_method) {
+  if ($payment_method->controller->name == 'PaymentMethodPOController') {
+    $payment_method->controller_data += $payment_method->controller->controller_data_defaults;
+    $query = db_insert('payment_method_po');
+    $values = array_merge($payment_method->controller_data, array(
+      'pmid' => $payment_method->pmid,
+    ));
+    $query->fields($values);
+    $query->execute();
+  }
+}
+
+/**
+ * Implements hook_ENTITY_TYPE_ACTION().
+ */
+function payment_method_po_payment_method_update(PaymentMethod $payment_method) {
+  if ($payment_method->controller->name == 'PaymentMethodPOController') {
+    $query = db_update('payment_method_po');
+    $values = array_merge($payment_method->controller_data, array(
+      'pmid' => $payment_method->pmid,
+    ));
+    $query->fields($values);
+    $query->condition('pmid', $payment_method->pmid);
+    $query->execute();
+  }
+}
+
+/**
+ * Implements hook_ENTITY_TYPE_ACTION().
+ */
+function payment_method_po_payment_method_delete($entity) {
+  if ($entity->controller->name == 'PaymentMethodPOController') {
+    db_delete('payment_method_po')
+      ->condition('pmid', $entity->pmid)
+      ->execute();
+  }
+}
+
+/**
+ * A Purchase Order payment method controller.
+ *
+ * This controller will execute a purchase order payment and set the status to pending until the purhcase order is fulfilled.
+ */
+class PaymentMethodPOController extends PaymentMethodController {
+
+  public $controller_data_defaults = array(
+    'message' => 'Your payment is pending purchase order verification',
+    'status' => PAYMENT_STATUS_PENDING,
+    'text_format' => '',
+  );
+
+  public $payment_method_configuration_form_elements_callback = 'payment_method_po_payment_method_configuration_form_elements';
+
+  public $payment_configuration_form_elements_callback = 'payment_method_po_payment_configuration_form_elements';
+
+  function __construct() {
+    $this->title = t('Purchase Order');
+    $this->description = t("A purchase order payment method that will set payment status to pending for manual verification.");
+  }
+
+  /**
+   * Implements PaymentMethodController::execute().
+   */
+  function execute(Payment $payment) {
+    //store the po number in the payment_po table
+    $query = db_insert('payment_po');
+    $values = array(
+      'pid' => $payment->pid,
+      'po_number' => $payment->method->controller_data['po_number'],
+    );
+    $query->fields($values);
+    $query->execute();
+    $payment->setStatus(new PaymentStatusItem($payment->method->controller_data['status']));
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validate(Payment $payment, PaymentMethod $payment_method, $strict) {
+    // This payment method controller does not have a minimum amount, so when
+    // the parent throws such an exception, catch it and do nothing.
+    try {
+      parent::validate($payment, $payment_method, $strict);
+    }
+    catch (PaymentValidationAmountBelowMinimumException $e) {
+    }
+  }
+}
+
+/**
+ * Form build callback: implements
+ * PaymentMethodController::payment_method_configuration_form_elements_callback.
+ *
+ * @return array
+ *   A Drupal form.
+ */
+function payment_method_po_payment_method_configuration_form_elements(array $form, array &$form_state) {
+  $controller_data = $form_state['payment_method']->controller_data;
+
+  $elements['status'] = array(
+    '#type' => 'select',
+    '#title' => t('Final payment status'),
+    '#description' => t('The status to give a payment after being processed by this payment method.'),
+    '#default_value' => isset($controller_data['status']) ? $controller_data['status'] : PAYMENT_STATUS_PENDING,
+    '#options' => payment_status_options(),
+  );
+  $elements['message'] = array(
+    '#type' => 'text_format',
+    '#title' => t('Payment form message'),
+    '#default_value' => isset($controller_data['message']) ? $controller_data['message'] : '',
+    '#format' => isset($controller_data['text_format']) ? $controller_data['text_format'] : filter_default_format(),
+  );
+
+  return $elements;
+}
+
+/**
+ * Implements form validate callback for
+ * payment_method_po_payment_method_configuration_form_elements().
+ */
+function payment_method_po_payment_method_configuration_form_elements_validate(array $element, array &$form_state) {
+  $values = drupal_array_get_nested_value($form_state['values'], $element['#parents']);
+  $form_state['payment_method']->controller_data['message'] = $values['message']['value'];
+  $form_state['payment_method']->controller_data['status'] = $values['status'];
+  $form_state['payment_method']->controller_data['text_format'] = $values['message']['format'];
+}
+
+/**
+ * Implements
+ * PaymentMethodController::payment_configuration_form_elements_callback.
+ */
+function payment_method_po_payment_configuration_form_elements(array $element, array &$form_state) {
+  $payment = $form_state['payment'];
+
+  $elements = array();
+  $elements['message'] = array(
+    '#type' => 'markup',
+    '#markup' => check_markup($payment->method->controller_data['message'], $payment->method->controller_data['text_format']),
+  );
+
+  return $elements;
+}
\ No newline at end of file
