/*
 * This file is part of the xTuple ERP: PostBooks Edition, a free and
 * open source Enterprise Resource Planning software suite,
 * Copyright (c) 1999-2009 by OpenMFG LLC, d/b/a xTuple.
 * It is licensed to you under the Common Public Attribution License
 * version 1.0, the full text of which (including xTuple-specific Exhibits)
 * is available at www.xtuple.com/CPAL.  By using this software, you agree
 * to be bound by its terms.
 */

#include "issueWoMaterialBatch.h"

#include <QVariant>
#include <QMessageBox>
#include "inputManager.h"
#include "distributeInventory.h"

/*
 *  Constructs a issueWoMaterialBatch as a child of 'parent', with the
 *  name 'name' and widget flags set to 'f'.
 *
 *  The dialog will by default be modeless, unless you set 'modal' to
 *  true to construct a modal dialog.
 */
issueWoMaterialBatch::issueWoMaterialBatch(QWidget* parent, const char* name, bool modal, Qt::WFlags fl)
    : XDialog(parent, name, modal, fl)
{
    setupUi(this);


    // signals and slots connections
    connect(_issue, SIGNAL(clicked()), this, SLOT(sIssue()));
    connect(_wo, SIGNAL(newId(int)), this, SLOT(sFillList()));
    connect(_close, SIGNAL(clicked()), this, SLOT(close()));
    init();
}

/*
 *  Destroys the object and frees any allocated resources
 */
issueWoMaterialBatch::~issueWoMaterialBatch()
{
    // no need to delete child widgets, Qt does it all for us
}

/*
 *  Sets the strings of the subwidgets using the current
 *  language.
 */
void issueWoMaterialBatch::languageChange()
{
    retranslateUi(this);
}


void issueWoMaterialBatch::init()
{
  _hasPush = FALSE;

  _wo->setType(cWoExploded | cWoIssued | cWoReleased);

  omfgThis->inputManager()->notify(cBCWorkOrder, this, _wo, SLOT(setId(int)));

  _womatl->addColumn(tr("Item Number"),  _itemColumn, Qt::AlignLeft,   true,  "item_number"   );
  _womatl->addColumn(tr("Description"),  -1,          Qt::AlignLeft,   true,  "itemdescrip"   );
  _womatl->addColumn(tr("UOM"),          _uomColumn,  Qt::AlignCenter, true,  "uom_name" );
  _womatl->addColumn(tr("Issue Method"), _itemColumn, Qt::AlignCenter, true,  "issuemethod" );
  _womatl->addColumn(tr("Required"),     _qtyColumn,  Qt::AlignRight,  true,  "required"  );
  _womatl->addColumn(tr("QOH"),          _qtyColumn,  Qt::AlignRight,  true,  "itemsite_qtyonhand"  );
  _womatl->addColumn(tr("Short"),        _qtyColumn,  Qt::AlignRight,  true,  "short"  );
}

enum SetResponse issueWoMaterialBatch::set(ParameterList &pParams)
{
  QVariant param;
  bool     valid;

  param = pParams.value("wo_id", &valid);
  if (valid)
  {
    _captive = TRUE;

    _wo->setId(param.toInt());
    _wo->setReadOnly(TRUE);
    _issue->setFocus();
  }

  return NoError;
}

void issueWoMaterialBatch::sIssue()
{
  XSqlQuery issue;
  issue.prepare("SELECT itemsite_id, "
                "       item_number, "
                "       warehous_code, "
                "       (COALESCE((SELECT SUM(itemloc_qty) "
                "                    FROM itemloc "
                "                   WHERE (itemloc_itemsite_id=itemsite_id)), 0.0) "
                "        >= roundQty(item_fractional, noNeg(itemuomtouom(itemsite_item_id, womatl_uom_id, NULL, womatl_qtyreq - womatl_qtyiss)))) AS isqtyavail "
                "  FROM womatl, itemsite, item, warehous "
                " WHERE ( (womatl_itemsite_id=itemsite_id) "
                "   AND (itemsite_item_id=item_id) "
                "   AND (itemsite_warehous_id=warehous_id) "
                "   AND (NOT ((item_type = 'R') OR (itemsite_controlmethod = 'N'))) "
                "   AND ((itemsite_controlmethod IN ('L', 'S')) OR (itemsite_loccntrl)) "
                "   AND (womatl_issuemethod IN ('S', 'M')) "
                "   AND (womatl_wo_id=:wo_id)); ");
  issue.bindValue(":wo_id", _wo->id());
  issue.exec();
  while(issue.next())
  {
    if(!(issue.value("isqtyavail").toBool()))
    {
      QMessageBox::critical(this, tr("Insufficient Inventory"),
        tr("Item Number %1 in Site %2 is a Multiple Location or\n"
           "Lot/Serial controlled Item which is short on Inventory.\n"
           "This transaction cannot be completed as is. Please make\n"
           "sure there is sufficient Quantity on Hand before proceeding.")
          .arg(issue.value("item_number").toString())
          .arg(issue.value("warehous_code").toString()));
      return;
    }
  }

  XSqlQuery rollback;
  rollback.prepare("ROLLBACK;");

  issue.exec("BEGIN;");	// because of possible lot, serial, or location distribution cancelations
  issue.prepare("SELECT issueWoMaterialBatch(:wo_id) AS result;");
  issue.bindValue(":wo_id", _wo->id());
  issue.exec();
  omfgThis->sWorkOrdersUpdated(_wo->id(), TRUE);

  if (issue.first())
  {
    if (issue.value("result").toInt() < 0)
    {
      rollback.exec();
      systemError( this, tr("A System Error occurred at issueWoMaterialBatch::%1, Work Order ID #%2, Error #%3.")
                         .arg(__LINE__)
                         .arg(_wo->id())
                         .arg(issue.value("result").toInt()) );
      return;
    }
    else
    {
      if (distributeInventory::SeriesAdjust(issue.value("result").toInt(), this) == XDialog::Rejected)
      {
        rollback.exec();
        QMessageBox::information( this, tr("Material Issue"), tr("Transaction Canceled") );
        return;
      }

      issue.exec("COMMIT;");

      if (_captive)
        accept();
      else
      {
        _wo->setId(-1);
        _wo->setFocus();
      }
    }
  }
  else
  {
    rollback.exec();
    systemError( this, tr("A System Error occurred at issueWoMaterialBatch::%1, Work Order ID #%2.")
                       .arg(__LINE__)
                       .arg(_wo->id()) );
    return;
  }
}

void issueWoMaterialBatch::sFillList()
{
  _womatl->clear();
  _issue->setEnabled(false);

  if (_wo->isValid())
  {
    QTreeWidgetItem * hitem = _womatl->headerItem();
    if (_wo->method() == "A")
      hitem->setText(4, tr("Required"));
    else
      hitem->setText(4, tr("Returned"));
     
    XSqlQuery womatl;
    womatl.prepare( "SELECT womatl_id, item_number,"
                    " (item_descrip1 || ' ' || item_descrip2) AS itemdescrip, uom_name,"
                    " CASE WHEN (womatl_issuemethod = 'S') THEN :push"
                    "      WHEN (womatl_issuemethod = 'L') THEN :pull"
                    "      WHEN (womatl_issuemethod = 'M') THEN :mixed"
                    "      ELSE :error"
                    " END AS issuemethod,"
                    " CASE "
                    "   WHEN (womatl_qtyreq >= 0) THEN "
                    "     noNeg(womatl_qtyreq - womatl_qtyiss) "
                    "   ELSE "
                    "     (womatl_qtyiss * -1) "
                    "   END AS required,"
                    " itemsite_qtyonhand,"
                    " abs(noneg((itemsite_qtyonhand - womatl_qtyreq) * -1)) AS short,"
                    " 'qty' AS required_xtnumericrole,"
                    " 'qty' AS itemsite_qtyonhand_xtnumericrole,"
                    " 'qty' AS short_xtnumericrole,"
                    " CASE WHEN (womatl_issuemethod = 'L') THEN 'blue'"
                    " END AS issuemethod_qtforegroundrole, "
                    " CASE WHEN (abs(noneg((itemsite_qtyonhand - womatl_qtyreq) * -1)) > 0.0) THEN 'red'"
                    " END AS short_qtforegroundrole "
                    "FROM womatl, itemsite, item, uom "
                    "WHERE ((womatl_itemsite_id=itemsite_id)"
                    " AND (itemsite_item_id=item_id)"
                    " AND (womatl_uom_id=uom_id)"
                    " AND (womatl_wo_id=:wo_id)) "
                    "ORDER BY item_number;" );
    womatl.bindValue(":push", tr("Push"));
    womatl.bindValue(":pull", tr("Pull"));
    womatl.bindValue(":mixed", tr("Mixed"));
    womatl.bindValue(":error", tr("Error"));
    womatl.bindValue(":wo_id", _wo->id());
    womatl.exec();
    _womatl->populate(womatl);
    _issue->setEnabled(true);
  }
}
